diff --git a/fv/callspec.pas b/fv/callspec.pas new file mode 100644 index 0000000000..b25caaeefa --- /dev/null +++ b/fv/callspec.pas @@ -0,0 +1,432 @@ +{ + $Id$ + + This unit provides compiler-independent mechanisms to call special + functions, i.e. local functions/procedures, constructors, methods, + destructors, etc. As there are no procedural variables for these + special functions, there is no Pascal way to call them directly. + + Copyright (c) 1997 Matthias K"oppe + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + ****************************************************************************} +unit CallSpec; + +{ + As of this version, the following compilers are supported. Please + port CallSpec to other compilers (including earlier versions) and + send your code to the above address. + + Compiler Comments + --------------------------- ------------------------------------- + Turbo Pascal 6.0 + Borland/Turbo Pascal 7.0 + FPC Pascal 0.99.8 +} + +interface + +{$i platform.inc} + +{ + The frame pointer points to the local variables of a procedure. + Use CurrentFramePointer to address the locals of the current procedure; + use PreviousFramePointer to addess the locals of the calling procedure. +} +type +{$ifdef BIT_16} + FramePointer = Word; +{$endif} +{$ifdef BIT_32} + FramePointer = pointer; +{$endif} + +function CurrentFramePointer: FramePointer; +function PreviousFramePointer: FramePointer; + +{ This version of CallSpec supports four classes of special functions. + (Please write if you need other classes.) + For each, two types of argument lists are allowed: + + `Void' indicates special functions with no explicit arguments. + Sample: constructor T.Init; + `Pointer' indicates special functions with one explicit pointer argument. + Sample: constructor T.Load(var S: TStream); +} + +{ Constructor calls. + + Ctor Pointer to the constructor. + Obj Pointer to the instance. NIL if new instance to be allocated. + VMT Pointer to the VMT (obtained by TypeOf()). + returns Pointer to the instance. +} +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; + +{ Method calls. + + Method Pointer to the method. + Obj Pointer to the instance. NIL if new instance to be allocated. + returns Pointer to the instance. +} +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; + +{ Local-function/procedure calls. + + Func Pointer to the local function (which must be far-coded). + Frame Frame pointer of the wrapping function. +} + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; + +{ Calls of functions/procedures local to methods. + + Func Pointer to the local function (which must be far-coded). + Frame Frame pointer of the wrapping method. + Obj Pointer to the object that the method belongs to. +} +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; + + +implementation + +{$ifdef PPC_FPC} + +{$ifdef CPUI386} +{$ASMMODE ATT} +{$endif CPUI386} + +{ This indicates an FPC version which uses the same call scheme for + method-local and procedure-local procedures, but which expects the + ESI register be loaded with the Self pointer in method-local procs. } + +type + VoidLocal = function(_EBP: FramePointer): pointer; + PointerLocal = function(_EBP: FramePointer; Param1: pointer): pointer; + VoidMethodLocal = function(_EBP: FRAMEPOINTER): pointer; + PointerMethodLocal = function(_EBP: FRAMEPOINTER; Param1: pointer): pointer; + VoidConstructor = function(VMT: pointer; Obj: pointer): pointer; + PointerConstructor = function(VMT: pointer; Obj: pointer; Param1: pointer): pointer; + VoidMethod = function(Obj: pointer): pointer; + PointerMethod = function(Obj: pointer; Param1: pointer): pointer; + + +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + + CallVoidConstructor := VoidConstructor(Ctor)(VMT, Obj) +end; + + +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerConstructor := PointerConstructor(Ctor)(VMT, Obj, Param1) +end; + + +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallVoidMethod := VoidMethod(Method)(Obj) +end; + + +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerMethod := PointerMethod(Method)(Obj, Param1) +end; + + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; +begin + CallVoidLocal := VoidLocal(Func)(Frame) +end; + + +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; +begin + CallPointerLocal := PointerLocal(Func)(Frame, Param1) +end; + + +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallVoidMethodLocal := VoidMethodLocal(Func)(Frame) +end; + + +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerMethodLocal := PointerMethodLocal(Func)(Frame, Param1) +end; + + +function CurrentFramePointer: FramePointer;assembler; +{$ifdef CPUI386} +asm + movl %ebp,%eax +end ['EAX']; +{$endif CPUI386} +{$ifdef CPU68K} +asm + move.l a6, d0 +end['D0']; +{$endif CPU68K} + + +function PreviousFramePointer: FramePointer;assembler; +{$ifdef CPUI386} +asm + movl (%ebp),%eax +end ['EAX']; +{$endif CPUI386} +{$ifdef CPU68K} +asm + move.l (a6), d0 +end['D0']; +{$endif CPU68K} + +{$endif PPC_FPC} + + +{$ifdef PPC_BP} +type + VoidConstructor = function(VmtOfs: Word; Obj: pointer): pointer; + PointerConstructor = function(Param1: pointer; VmtOfs: Word; Obj: pointer): pointer; + VoidMethod = function(Obj: pointer): pointer; + PointerMethod = function(Param1: pointer; Obj: pointer): pointer; + +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +begin + CallVoidConstructor := VoidConstructor(Ctor)(Ofs(VMT^), Obj) +end; + + +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; +begin + CallPointerConstructor := PointerConstructor(Ctor)(Param1, Ofs(VMT^), Obj) +end; + + +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +begin + CallVoidMethod := VoidMethod(Method)(Obj) +end; + + +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; +begin + CallPointerMethod := PointerMethod(Method)(Param1, Obj) +end; + + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; assembler; +asm +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; assembler; +asm + mov ax, word ptr Param1 + mov dx, word ptr Param1+2 + push dx + push ax +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; assembler; +asm +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; assembler; +asm + mov ax, word ptr Param1 + mov dx, word ptr Param1+2 + push dx + push ax +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CurrentFramePointer: FramePointer; assembler; +asm + mov ax, bp +end; + + +function PreviousFramePointer: FramePointer; assembler; +asm + mov ax, ss:[bp] +end; + +{$endif PPC_BP} + + +end. +{ + $Log$ + Revision 1.1 2001-08-05 02:10:26 peter + * more files + + Revision 1.3 2001/07/30 08:27:58 pierre + * fix I386 compilation problem + + Revision 1.2 2001/07/29 20:23:18 pierre + * support for m68k cpu + + Revision 1.1 2001/01/29 21:56:04 peter + * updates for new fpcmake + + Revision 1.1 2001/01/29 11:31:26 marco + * added from API. callspec renamed to .pp + + Revision 1.1 2000/07/13 06:29:38 michael + + Initial import + + Revision 1.1 2000/01/06 01:20:30 peter + * moved out of packages/ back to topdir + + Revision 1.1 1999/12/23 19:36:47 peter + * place unitfiles in target dirs + + Revision 1.1 1999/11/24 23:36:37 peter + * moved to packages dir + + Revision 1.2 1998/12/16 21:57:16 peter + * fixed currentframe,previousframe + + testcall to test the callspec unit + + Revision 1.1 1998/12/04 12:48:24 peter + * moved some dirs + + Revision 1.5 1998/12/04 09:53:44 peter + * removed objtemp global var + + Revision 1.4 1998/11/24 17:14:24 peter + * fixed esi loading + + + Date Version Who Comments + ---------- -------- ------- ------------------------------------- + 19-Sep-97 0.1 mkoeppe Initial version. + 22-Sep-97 0.11 fk 0.9.3 support added, self isn't expected + on the stack in local procedures of methods + 23-Sep-97 0.12 mkoeppe Cleaned up 0.9.3 conditionals. + 03-Oct-97 0.13 mkoeppe Fixed esi load in FPC 0.9 + 22-Oct-98 0.14 pfv 0.99.8 support for FPC +} diff --git a/fv/editors.pas b/fv/editors.pas new file mode 100644 index 0000000000..ad98c3e9f6 --- /dev/null +++ b/fv/editors.pas @@ -0,0 +1,3733 @@ +unit Editors; + +{$i platform.inc} + +{$ifdef PPC_FPC} + {$H-} +{$else} + {$F+,O+,E+,N+} +{$endif} +{$X+,R-,I-,Q-,V-} +{$ifndef OS_LINUX} + {$S-} +{$endif} + + +{$define UNIXLF} + +interface + +uses + Objects, Drivers,Views,Dialogs,FVCommon,FVConsts; + +const + { Length constants. } + Tab_Stop_Length = 74; + +{$ifdef PPC_BP} + MaxLineLength = 1024; + MinBufLength = $1000; + MaxBufLength = $ff00; + NotFoundValue = $ffff; + LineInfoGrow = 256; + MaxLines = 16000; +{$else} + MaxLineLength = 4096; + MinBufLength = $1000; + MaxBufLength = $7fffff00; + NotFoundValue = $ffffffff; + LineInfoGrow = 1024; + MaxLines = $7ffffff; +{$endif} + + + { Editor constants for dialog boxes. } + edOutOfMemory = 0; + edReadError = 1; + edWriteError = 2; + edCreateError = 3; + edSaveModify = 4; + edSaveUntitled = 5; + edSaveAs = 6; + edFind = 7; + edSearchFailed = 8; + edReplace = 9; + edReplacePrompt = 10; + + edJumpToLine = 11; + edPasteNotPossible = 12; + edReformatDocument = 13; + edReformatNotAllowed = 14; + edReformNotPossible = 15; + edReplaceNotPossible = 16; + edRightMargin = 17; + edSetTabStops = 18; + edWrapNotPossible = 19; + + { Editor flag constants for dialog options. } + efCaseSensitive = $0001; + efWholeWordsOnly = $0002; + efPromptOnReplace = $0004; + efReplaceAll = $0008; + efDoReplace = $0010; + efBackupFiles = $0100; + + { Constants for object palettes. } + CIndicator = #2#3; + CEditor = #6#7; + CMemo = #26#27; + +type + TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word; + + PIndicator = ^TIndicator; + TIndicator = object (TView) + Location : Objects.TPoint; + Modified : Boolean; + AutoIndent : Boolean; { Added boolean for AutoIndent mode. } + WordWrap : Boolean; { Added boolean for WordWrap mode. } + constructor Init (var Bounds : TRect); + procedure Draw; virtual; + function GetPalette : PPalette; virtual; + procedure SetState (AState : Word; Enable : Boolean); virtual; + procedure SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean; + IsModified : Boolean; + IsWordWrap : Boolean); + end; + + TLineInfoRec = record + Len,Attr : Sw_word; + end; + TLineInfoArr = array[0..MaxLines] of TLineInfoRec; + PLineInfoArr = ^TLineInfoArr; + + PLineInfo = ^TLineInfo; + TLineInfo = object + Info : PLineInfoArr; + MaxPos : Sw_Word; + constructor Init; + destructor Done; + procedure Grow(pos:Sw_word); + procedure SetLen(pos,val:Sw_Word); + procedure SetAttr(pos,val:Sw_Word); + function GetLen(pos:Sw_Word):Sw_Word; + function GetAttr(pos:Sw_Word):Sw_Word; + end; + + + PEditBuffer = ^TEditBuffer; + TEditBuffer = array[0..MaxBufLength] of Char; + + PEditor = ^TEditor; + TEditor = object (TView) + HScrollBar : PScrollBar; + VScrollBar : PScrollBar; + Indicator : PIndicator; + Buffer : PEditBuffer; + BufSize : Sw_Word; + BufLen : Sw_Word; + GapLen : Sw_Word; + SelStart : Sw_Word; + SelEnd : Sw_Word; + CurPtr : Sw_Word; + CurPos : Objects.TPoint; + Delta : Objects.TPoint; + Limit : Objects.TPoint; + DrawLine : Sw_Integer; + DrawPtr : Sw_Word; + DelCount : Sw_Word; + InsCount : Sw_Word; + Flags : Longint; + IsReadOnly : Boolean; + IsValid : Boolean; + CanUndo : Boolean; + Modified : Boolean; + Selecting : Boolean; + Overwrite : Boolean; + AutoIndent : Boolean; + NoSelect : Boolean; + TabSize : Sw_Word; { tabsize for displaying } + BlankLine : Sw_Word; { First blank line after a paragraph. } + Word_Wrap : Boolean; { Added boolean to toggle wordwrap on/off. } + Line_Number : string[8]; { Holds line number to jump to. } + Right_Margin : Sw_Integer; { Added integer to set right margin. } + Tab_Settings : String[Tab_Stop_Length]; { Added string to hold tab stops. } + + constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; ABufSize : Sw_Word); + constructor Load (var S : Objects.TStream); + destructor Done; virtual; + function BufChar (P : Sw_Word) : Char; + function BufPtr (P : Sw_Word) : Sw_Word; + procedure ChangeBounds (var Bounds : TRect); virtual; + procedure ConvertEvent (var Event : Drivers.TEvent); virtual; + function CursorVisible : Boolean; + procedure DeleteSelect; + procedure DoneBuffer; virtual; + procedure Draw; virtual; + procedure FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual; + function GetPalette : PPalette; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure InitBuffer; virtual; + function InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean; + function InsertFrom (Editor : PEditor) : Boolean; virtual; + function InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean; + procedure ScrollTo (X, Y : Sw_Integer); + function Search (const FindStr : String; Opts : Word) : Boolean; + function SetBufSize (NewSize : Sw_Word) : Boolean; virtual; + procedure SetCmdState (Command : Word; Enable : Boolean); + procedure SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean); + procedure SetCurPtr (P : Sw_Word; SelectMode : Byte); + procedure SetState (AState : Word; Enable : Boolean); virtual; + procedure Store (var S : Objects.TStream); + procedure TrackCursor (Center : Boolean); + procedure Undo; + procedure UpdateCommands; virtual; + function Valid (Command : Word) : Boolean; virtual; + + private + KeyState : Integer; + LockCount : Byte; + UpdateFlags : Byte; + Place_Marker : Array [1..10] of Sw_Word; { Inserted array to hold place markers. } + Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. } + + procedure Center_Text (Select_Mode : Byte); + function CharPos (P, Target : Sw_Word) : Sw_Integer; + function CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word; + procedure Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean); + function ClipCopy : Boolean; + procedure ClipCut; + procedure ClipPaste; + procedure DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean); + procedure DoSearchReplace; + procedure DoUpdate; + function Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean; + procedure DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word); + procedure Find; + function GetMousePtr (Mouse : Objects.TPoint) : Sw_Word; + function HasSelection : Boolean; + procedure HideSelect; + procedure Insert_Line (Select_Mode : Byte); + function IsClipboard : Boolean; + procedure Jump_Place_Marker (Element : Byte; Select_Mode : Byte); + procedure Jump_To_Line (Select_Mode : Byte); + function LineEnd (P : Sw_Word) : Sw_Word; + function LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word; + function LineStart (P : Sw_Word) : Sw_Word; + function LineNr (P : Sw_Word) : Sw_Word; + procedure Lock; + function NewLine (Select_Mode : Byte) : Boolean; + function NextChar (P : Sw_Word) : Sw_Word; + function NextLine (P : Sw_Word) : Sw_Word; + function NextWord (P : Sw_Word) : Sw_Word; + function PrevChar (P : Sw_Word) : Sw_Word; + function PrevLine (P : Sw_Word) : Sw_Word; + function PrevWord (P : Sw_Word) : Sw_Word; + procedure Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean); + function Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean; + procedure Remove_EOL_Spaces (Select_Mode : Byte); + procedure Replace; + procedure Scroll_Down; + procedure Scroll_Up; + procedure Select_Word; + procedure SetBufLen (Length : Sw_Word); + procedure Set_Place_Marker (Element : Byte); + procedure Set_Right_Margin; + procedure Set_Tabs; + procedure StartSelect; + procedure Tab_Key (Select_Mode : Byte); + procedure ToggleInsMode; + procedure Unlock; + procedure Update (AFlags : Byte); + procedure Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word); + end; + + TMemoData = record + Length : Sw_Word; + Buffer : TEditBuffer; + end; + + PMemo = ^TMemo; + TMemo = object (TEditor) + constructor Load (var S : Objects.TStream); + function DataSize : Sw_Word; virtual; + procedure GetData (var Rec); virtual; + function GetPalette : PPalette; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure SetData (var Rec); virtual; + procedure Store (var S : Objects.TStream); + end; + + PFileEditor = ^TFileEditor; + TFileEditor = object (TEditor) + FileName : FNameStr; + constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; AFileName : FNameStr); + constructor Load (var S : Objects.TStream); + procedure DoneBuffer; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure InitBuffer; virtual; + function LoadFile : Boolean; + function Save : Boolean; + function SaveAs : Boolean; + function SaveFile : Boolean; + function SetBufSize (NewSize : Sw_Word) : Boolean; virtual; + procedure Store (var S : Objects.TStream); + procedure UpdateCommands; virtual; + function Valid (Command : Word) : Boolean; virtual; + end; + + PEditWindow = ^TEditWindow; + TEditWindow = object (TWindow) + Editor : PFileEditor; + constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer); + constructor Load (var S : Objects.TStream); + procedure Close; virtual; + function GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure SizeLimits(var Min, Max: TPoint); virtual; + procedure Store (var S : Objects.TStream); + end; + + +function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word; +function CreateFindDialog: PDialog; +function CreateReplaceDialog: PDialog; +function JumpLineDialog : PDialog; +function ReformDocDialog : PDialog; +function RightMarginDialog : PDialog; +function TabStopDialog : Dialogs.PDialog; +function StdEditorDialog(Dialog: Integer; Info: Pointer): Word; + +const + WordChars : set of Char = ['!'..#255]; + + LineBreak : string[2]= +{$ifdef UNIXLF} + #10; +{$else} + #13#10; +{$endif} + + + { The Allow_Reformat boolean is a programmer hook. } + { I've placed this here to allow programmers to } + { determine whether or not paragraph and document } + { reformatting are allowed if Word_Wrap is not } + { active. Some people say don't allow, and others } + { say allow it. I've left it up to the programmer. } + { Set to FALSE if not allowed, or TRUE if allowed. } + Allow_Reformat : Boolean = True; + + EditorDialog : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog; + EditorFlags : Word = efBackupFiles + efPromptOnReplace; + FindStr : String[80] = ''; + ReplaceStr : String[80] = ''; + Clipboard : PEditor = nil; + + ToClipCmds : TCommandSet = ([cmCut,cmCopy,cmClear]); + FromClipCmds : TCommandSet = ([cmPaste]); + UndoCmds : TCommandSet = ([cmUndo,cmRedo]); + +TYPE + TFindDialogRec = packed record + Find : String[80]; + Options : Word; + end; + + TReplaceDialogRec = packed record + Find : String[80]; + Replace : String[80]; + Options : Word; + end; + + TRightMarginRec = packed record + Margin_Position : String[3]; + end; + + TTabStopRec = packed record + Tab_String : String [Tab_Stop_Length]; + end; + +CONST + { VMT constants. } + REditor : TStreamRec = (ObjType : 70; + VmtLink : Ofs (TypeOf (TEditor)^); + Load : @TEditor.Load; + Store : @TEditor.Store); + + RMemo : TStreamRec = (ObjType : 71; + VmtLink : Ofs (TypeOf (TMemo)^); + Load : @TMemo.Load; + Store : @TMemo.Store); + + RFileEditor : TStreamRec = (ObjType : 72; + VmtLink : Ofs (TypeOf (TFileEditor)^); + Load : @TFileEditor.Load; + Store : @TFileEditor.Store); + + RIndicator : TStreamRec = (ObjType : 73; + VmtLink : Ofs (TypeOf (TIndicator)^); + Load : @TIndicator.Load; + Store : @TIndicator.Store); + + REditWindow : TStreamRec = (ObjType : 74; + VmtLink : Ofs (TypeOf (TEditWindow)^); + Load : @TEditWindow.Load; + Store : @TEditWindow.Store); + +procedure RegisterEditors; + + +{**************************************************************************** + Implementation +****************************************************************************} + +implementation + +uses + Memory, Dos, App, StdDlg, MsgBox, Resource; + +type + pword = ^word; + +CONST + { Update flag constants. } + ufUpdate = $01; + ufLine = $02; + ufView = $04; + ufStats = $05; + + { SelectMode constants. } + smExtend = $01; + smDouble = $02; + + sfSearchFailed = NotFoundValue; + + { Arrays that hold all the command keys and options. } + FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A), cmWordLeft, + Ord (^B), cmReformPara, + Ord (^C), cmPageDown, + Ord (^D), cmCharRight, + Ord (^E), cmLineUp, + Ord (^F), cmWordRight, + Ord (^G), cmDelChar, + Ord (^H), cmBackSpace, + Ord (^I), cmTabKey, + Ord (^J), $FF04, + Ord (^K), $FF02, + Ord (^L), cmSearchAgain, + Ord (^M), cmNewLine, + Ord (^N), cmInsertLine, + Ord (^O), $FF03, + Ord (^Q), $FF01, + Ord (^R), cmPageUp, + Ord (^S), cmCharLeft, + Ord (^T), cmDelWord, + Ord (^U), cmUndo, + Ord (^V), cmInsMode, + Ord (^W), cmScrollUp, + Ord (^X), cmLineDown, + Ord (^Y), cmDelLine, + Ord (^Z), cmScrollDown, + kbLeft, cmCharLeft, + kbRight, cmCharRight, + kbCtrlLeft, cmWordLeft, + kbCtrlRight, cmWordRight, + kbHome, cmLineStart, + kbEnd, cmLineEnd, + kbCtrlHome, cmHomePage, + kbCtrlEnd, cmEndPage, + kbUp, cmLineUp, + kbDown, cmLineDown, + kbPgUp, cmPageUp, + kbPgDn, cmPageDown, + kbCtrlPgUp, cmTextStart, + kbCtrlPgDn, cmTextEnd, + kbIns, cmInsMode, + kbDel, cmDelChar, + kbCtrlBack, cmDelStart, + kbShiftIns, cmPaste, + kbShiftDel, cmCut, + kbCtrlIns, cmCopy, + kbCtrlDel, cmClear); + + { SCRLUP - Stop. } { Added ^W to scroll screen up. } + { SCRLDN - Stop. } { Added ^Z to scroll screen down. } + { REFORM - Stop. } { Added ^B for paragraph reformatting. } + { PRETAB - Stop. } { Added ^I for preset tabbing. } + { JLINE - Stop. } { Added ^J to jump to a line number. } + { INSLIN - Stop. } { Added ^N to insert line at cursor. } + { INDENT - Stop. } { Removed ^O and put it into ^QI. } + { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. } + { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH. } + + QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0, + Ord ('1'), cmJumpMark1, + Ord ('2'), cmJumpMark2, + Ord ('3'), cmJumpMark3, + Ord ('4'), cmJumpMark4, + Ord ('5'), cmJumpMark5, + Ord ('6'), cmJumpMark6, + Ord ('7'), cmJumpMark7, + Ord ('8'), cmJumpMark8, + Ord ('9'), cmJumpMark9, + Ord ('A'), cmReplace, + Ord ('C'), cmTextEnd, + Ord ('D'), cmLineEnd, + Ord ('F'), cmFind, + Ord ('H'), cmDelStart, + Ord ('I'), cmIndentMode, + Ord ('L'), cmUndo, + Ord ('R'), cmTextStart, + Ord ('S'), cmLineStart, + Ord ('U'), cmReformDoc, + Ord ('Y'), cmDelEnd); + + { UNDO - Stop. } { Added IDE undo feature of ^QL. } + { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. } + { MARK - Stop. } { Added cmJumpMark# to allow place marking. } + { INDENT - Stop. } { Moved IndentMode here from Firstkeys. } + + BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0, + Ord ('1'), cmSetMark1, + Ord ('2'), cmSetMark2, + Ord ('3'), cmSetMark3, + Ord ('4'), cmSetMark4, + Ord ('5'), cmSetMark5, + Ord ('6'), cmSetMark6, + Ord ('7'), cmSetMark7, + Ord ('8'), cmSetMark8, + Ord ('9'), cmSetMark9, + Ord ('B'), cmStartSelect, + Ord ('C'), cmPaste, + Ord ('D'), cmSave, + Ord ('F'), cmSaveAs, + Ord ('H'), cmHideSelect, + Ord ('K'), cmCopy, + Ord ('S'), cmSave, + Ord ('T'), cmSelectWord, + Ord ('Y'), cmCut, + Ord ('X'), cmSaveDone); + + { SELWRD - Stop. } { Added ^KT to select word only. } + { SAVE - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands. } + { MARK - Stop. } { Added cmSetMark# to allow place marking. } + + FormatKeys : array[0..5 * 2] of Word = (5, Ord ('C'), cmCenterText, + Ord ('T'), cmCenterText, + Ord ('I'), cmSetTabs, + Ord ('R'), cmRightMargin, + Ord ('W'), cmWordWrap); + + { WRAP - Stop. } { Added Wordwrap feature if ^OW pressed. } + { RMSET - Stop. } { Added set right margin feature if ^OR pressed. } + { PRETAB - Stop. } { Added preset tab feature if ^OI pressed. } + { CENTER - Stop. } { Added center text option ^OC for a line. } + + JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine); + + { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. } + + KeyMap : array[0..4] of Pointer = (@FirstKeys, + @QuickKeys, + @BlockKeys, + @FormatKeys, + @JumpKeys); + + { WRAP - Stop. } { Added @FormatKeys for new ^O? keys. } + { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. } + { JLINE - Stop. } { Added @JumpKeys for new ^J? keys. } + { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. } + + +{**************************************************************************** + Dialogs +****************************************************************************} + +function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word; +begin + DefEditorDialog := cmCancel; +end; { DefEditorDialog } + + +function CreateFindDialog: PDialog; +var + D: PDialog; + Control: PView; + R: TRect; +begin + R.Assign(0, 0, 38, 12); + D := New(PDialog, Init(R, strings^.get(sFind))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign(3, 3, 32, 4); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDFindText; + Insert(Control); + R.Assign(2, 2, 15, 3); + Insert(New(PLabel, Init(R, labels^.get(slTextToFind), Control))); + R.Assign(32, 3, 35, 4); + Insert(New(PHistory, Init(R, PInputLine(Control), 10))); + + R.Assign(3, 5, 35, 7); + Control := New(PCheckBoxes, Init(R, + NewSItem (labels^.get(slCaseSensitive), + NewSItem (labels^.get(slWholeWordsOnly),nil)))); + Control^.HelpCtx := hcCCaseSensitive; + Insert(Control); + + R.Assign(14, 9, 24, 11); + Control := New (PButton, Init(R,labels^.get(slOK),cmOk,bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + Inc(R.A.X, 12); Inc(R.B.X, 12); + Control := New (PButton, Init(R,labels^.get(slCancel),cmCancel, bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext(False); + end; + CreateFindDialog := D; +end; + + +function CreateReplaceDialog: PDialog; +var + D: PDialog; + Control: PView; + R: TRect; +begin + R.Assign(0, 0, 40, 16); + D := New(PDialog, Init(R,labels^.get(slReplace))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign(3, 3, 34, 4); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDFindText; + Insert(Control); + R.Assign(2, 2, 15, 3); + Insert(New(PLabel, Init(R,labels^.get(slTextToFind), Control))); + R.Assign(34, 3, 37, 4); + Insert(New(PHistory, Init(R, PInputLine(Control), 10))); + + R.Assign(3, 6, 34, 7); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDReplaceText; + Insert(Control); + R.Assign(2, 5, 12, 6); + Insert(New(PLabel, Init(R,labels^.get(slNewText), Control))); + R.Assign(34, 6, 37, 7); + Insert(New(PHistory, Init(R, PInputLine(Control), 11))); + + R.Assign(3, 8, 37, 12); + Control := New (Dialogs.PCheckBoxes, Init (R, + NewSItem (labels^.get(slCasesensitive), + NewSItem (labels^.get(slWholewordsonly), + NewSItem (labels^.get(slPromptonreplace), + NewSItem (labels^.get(slReplaceall), nil)))))); + Control^.HelpCtx := hcCCaseSensitive; + Insert (Control); + + R.Assign (8, 13, 18, 15); + Control := New (PButton, Init (R,labels^.get(slOK), cmOk, bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (22, 13, 32, 15); + Control := New (PButton, Init (R,labels^.get(slCancel), cmCancel, bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext(False); + end; + CreateReplaceDialog := D; +end; + + +function JumpLineDialog : PDialog; +VAR + D : PDialog; + R : TRect; + Control: PView; +Begin + R.Assign (0, 0, 26, 8); + D := New(PDialog, Init(R,strings^.get(sJumpTo))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (3, 2, 15, 3); + Control := New (Dialogs.PStaticText, Init (R,labels^.get(slLineNumber))); + Insert (Control); + + R.Assign (15, 2, 21, 3); + Control := New (Dialogs.PInputLine, Init (R, 4)); + Control^.HelpCtx := hcDLineNumber; + Insert (Control); + + R.Assign (21, 2, 24, 3); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12))); + + R.Assign (2, 5, 12, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (14, 5, 24, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + JumpLineDialog := D; +end; { JumpLineDialog } + + +function ReformDocDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that asks where to start reformatting the document. } +VAR + R : TRect; + D : Dialogs.PDialog; + Control : PView; +Begin + R.Assign (0, 0, 32, 11); + D := New (Dialogs.PDialog, Init (R, strings^.get(sReformatDocument))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (2, 2, 30, 3); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSelectWhereToBegin))); + Insert (Control); + + R.Assign (3, 3, 29, 4); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sReformattingTheDocument))); + Insert (Control); + + R.Assign (50, 5, 68, 6); + Control := New (Dialogs.PLabel, Init (R, strings^.get(sReformatDocument), Control)); + Insert (Control); + + R.Assign (5, 5, 26, 7); + Control := New (Dialogs.PRadioButtons, Init (R, + NewSItem (labels^.get(slCurrentLine), + NewSItem (labels^.get(slEntireDocument), Nil)))); + Control^.HelpCtx := hcDReformDoc; + Insert (Control); + + R.Assign (4, 8, 14, 10); + Control := New (Dialogs.PButton, Init (R,labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (17, 8, 27, 10); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + ReformDocDialog := D; +end; { ReformDocDialog } + + +function RightMarginDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that allows the user to change the Right_Margin. } +VAR + R : TRect; + D : PDialog; + Control : PView; +Begin + R.Assign (0, 0, 26, 8); + D := New (Dialogs.PDialog, Init (R, strings^.get(sRightMargin))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (5, 2, 13, 3); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSetting))); + Insert (Control); + + R.Assign (13, 2, 18, 3); + Control := New (Dialogs.PInputLine, Init (R, 3)); + Control^.HelpCtx := hcDRightMargin; + Insert (Control); + + R.Assign (18, 2, 21, 3); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13))); + + R.Assign (2, 5, 12, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (14, 5, 24, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + RightMarginDialog := D; +end; { RightMarginDialog; } + + +function TabStopDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that allows the user to set their own tab stops. } +VAR + Index : Sw_Integer; { Local Indexing variable. } + R : TRect; + D : PDialog; + Control : PView; + Tab_Stop : String[2]; { Local string to print tab column number. } +Begin + R.Assign (0, 0, 80, 8); + D := New (Dialogs.PDialog, Init (R, strings^.get(sTabSettings))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (2, 2, 77, 3); + Control := New (Dialogs.PStaticText, Init (R, + ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....')); + Insert (Control); + + for Index := 1 to 7 do + begin + R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2); + Str (Index * 10, Tab_Stop); + Control := New (Dialogs.PStaticText, Init (R, Tab_Stop)); + Insert (Control); + end; + + R.Assign (2, 3, 78, 4); + Control := New (Dialogs.PInputLine, Init (R, 74)); + Control^.HelpCtx := hcDTabStops; + Insert (Control); + + R.Assign (38, 5, 41, 6); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14))); + + R.Assign (27, 5, 37, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (42, 5, 52, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + SelectNext (False); + end; + TabStopDialog := D; +end { TabStopDialog }; + + +function StdEditorDialog(Dialog: Integer; Info: Pointer): Word; +var + R: TRect; + T: TPoint; +begin + case Dialog of + edOutOfMemory: + StdEditorDialog := MessageBox(strings^.get(sOutOfMemory), nil, mfError + mfOkButton); + edReadError: + StdEditorDialog := MessageBox(strings^.get(sFileReadError), @Info, mfError + mfOkButton); + edWriteError: + StdEditorDialog := MessageBox(strings^.get(sFileWriteError), @Info, mfError + mfOkButton); + edCreateError: + StdEditorDialog := MessageBox(strings^.get(sFileCreateError), @Info, mfError + mfOkButton); + edSaveModify: + StdEditorDialog := MessageBox(strings^.get(sModified), @Info, mfInformation + mfYesNoCancel); + edSaveUntitled: + StdEditorDialog := MessageBox(strings^.get(sFileUntitled), nil, mfInformation + mfYesNoCancel); + edSaveAs: + StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*', + labels^.get(slSaveFileAs), labels^.get(slName), fdOkButton, 101)), Info); + edFind: + StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info); + edSearchFailed: + StdEditorDialog := MessageBox(strings^.get(sSearchStringNotFound), nil, mfError + mfOkButton); + edReplace: + StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info); + edReplacePrompt: + begin + { Avoid placing the dialog on the same line as the cursor } + R.Assign(0, 1, 40, 8); + R.Move((Desktop^.Size.X - R.B.X) div 2, 0); + Desktop^.MakeGlobal(R.B, T); + Inc(T.Y); + if PPoint(Info)^.Y <= T.Y then + R.Move(0, Desktop^.Size.Y - R.B.Y - 2); + StdEditorDialog := MessageBoxRect(R, strings^.get(sReplaceThisOccurence), + nil, mfYesNoCancel + mfInformation); + end; + edJumpToLine: + StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info); + edSetTabStops: + StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info); + edPasteNotPossible: + StdEditorDialog := MessageBox (strings^.get(sPasteNotPossible), nil, mfError + mfOkButton); + edReformatDocument: + StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info); + edReformatNotAllowed: + StdEditorDialog := MessageBox (strings^.get(sWordWrapOff), nil, mfError + mfOkButton); + edReformNotPossible: + StdEditorDialog := MessageBox (strings^.get(sReformatNotPossible), nil, mfError + mfOkButton); + edReplaceNotPossible: + StdEditorDialog := MessageBox (strings^.get(sReplaceNotPossible), nil, mfError + mfOkButton); + edRightMargin: + StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info); + edWrapNotPossible: + StdEditorDialog := MessageBox (strings^.get(sWordWrapNotPossible), nil, mfError + mfOKButton); + else + StdEditorDialog := MessageBox (strings^.get(sUnknownDialog), nil, mfError + mfOkButton); + end; +end; + + +{**************************************************************************** + Helpers +****************************************************************************} + +function CountLines(var Buf; Count: sw_Word): sw_Integer; +var + p : pchar; + lines : sw_word; +begin + p:=pchar(@buf); + lines:=0; + while (count>0) do + begin + if p^ in [#10,#13] then + begin + inc(lines); + if ord((p+1)^)+ord(p^)=23 then + begin + inc(p); + dec(count); + if count=0 then + break; + end; + end; + inc(p); + dec(count); + end; + CountLines:=Lines; +end; + + +procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint); +{ Get the limits needed for Buf, its an extended version of countlines (lim.y), + which also gets the maximum line length in lim.x } +var + p : pchar; + len : sw_word; +begin + lim.x:=0; + lim.y:=0; + len:=0; + p:=pchar(@buf); + while (count>0) do + begin + if p^ in [#10,#13] then + begin + if len>lim.x then + lim.x:=len; + inc(lim.y); + if ord((p+1)^)+ord(p^)=23 then + begin + inc(p); + dec(count); + end; + len:=0; + end + else + inc(len); + inc(p); + dec(count); + end; +end; + + +function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word; +var + p : pword; + count : sw_word; +begin + p:=keymap; + count:=p^; + inc(p); + while (count>0) do + begin + if (lo(p^)=lo(keycode)) and + ((hi(p^)=0) or (hi(p^)=hi(keycode))) then + begin + inc(p); + scankeymap:=p^; + exit; + end; + inc(p,2); + dec(count); + end; + scankeymap:=0; +end; + + +Type + Btable = Array[0..255] of Byte; +Procedure BMMakeTable(const s:string; Var t : Btable); +{ Makes a Boyer-Moore search table. s = the search String t = the table } +Var + x : sw_integer; +begin + FillChar(t,sizeof(t),length(s)); + For x := length(s) downto 1 do + if (t[ord(s[x])] = length(s)) then + t[ord(s[x])] := length(s) - x; +end; + + +function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word; +Var + buffer : Array[0..MaxBufLength-1] of Byte Absolute block; + s2 : String; + len, + numb : Sw_Word; + found : Boolean; + bt : Btable; +begin + BMMakeTable(str,bt); + len:=length(str); + s2[0]:=chr(len); { sets the length to that of the search String } + found:=False; + numb:=pred(len); + While (not found) and (numb<(size-len)) do + begin + { partial match } + if buffer[numb] = ord(str[len]) then + begin + { less partial! } + if buffer[numb-pred(len)] = ord(str[1]) then + begin + move(buffer[numb-pred(len)],s2[1],len); + if (str=s2) then + begin + found:=true; + break; + end; + end; + inc(numb); + end + else + inc(numb,Bt[buffer[numb]]); + end; + if not found then + Scan := NotFoundValue + else + Scan := numb - pred(len); +end; + + +function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word; +Var + buffer : Array[0..MaxBufLength-1] of Char Absolute block; + s : String; + len, + numb, + x : Sw_Word; + found : Boolean; + bt : Btable; + p : pchar; + c : char; +begin + len:=length(str); + { create uppercased string } + s[0]:=chr(len); + for x:=1to len do + begin + if str[x] in ['a'..'z'] then + s[x]:=chr(ord(str[x])-32) + else + s[x]:=str[x]; + end; + BMMakeTable(s,bt); + found:=False; + numb:=pred(len); + While (not found) and (numb<(size-len)) do + begin + { partial match } + c:=buffer[numb]; + if c in ['a'..'z'] then + c:=chr(ord(c)-32); + if (c=s[len]) then + begin + { less partial! } + p:=@buffer[numb-pred(len)]; + x:=1; + while (x<=len) do + begin + if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or + (p^=s[x])) then + break; + inc(p); + inc(x); + end; + if (x>len) then + begin + found:=true; + break; + end; + inc(numb); + end + else + inc(numb,Bt[ord(c)]); + end; + if not found then + IScan := NotFoundValue + else + IScan := numb - pred(len); +end; + + +{**************************************************************************** + TIndicator +****************************************************************************} + +constructor TIndicator.Init (var Bounds : TRect); +begin + Inherited Init (Bounds); + GrowMode := gfGrowLoY + gfGrowHiY; +end; { TIndicator.Init } + + +procedure TIndicator.Draw; +VAR + Color : Byte; + Frame : Char; + L : array[0..1] of Longint; + S : String[15]; + B : TDrawBuffer; +begin + if State and sfDragging = 0 then + begin + Color := GetColor (1); + Frame := #205; + end + else + begin + Color := GetColor (2); + Frame := #196; + end; + MoveChar (B, Frame, Color, Size.X); + { If the text has been modified, put an 'M' in the TIndicator display. } + if Modified then + WordRec (B[1]).Lo := 77; + { If WordWrap is active put a 'W' in the TIndicator display. } + if WordWrap then + WordRec (B[2]).Lo := 87 + else + WordRec (B[2]).Lo := Byte (Frame); + { If AutoIndent is active put an 'I' in TIndicator display. } + if AutoIndent then + WordRec (B[0]).Lo := 73 + else + WordRec (B[0]).Lo := Byte (Frame); + L[0] := Location.Y + 1; + L[1] := Location.X + 1; + FormatStr (S, ' %d:%d ', L); + MoveStr (B[9 - Pos (':', S)], S, Color); { Changed original 8 to 9. } + WriteBuf (0, 0, Size.X, 1, B); +end; { TIndicator.Draw } + + +function TIndicator.GetPalette : PPalette; +const + P : string[Length (CIndicator)] = CIndicator; +begin + GetPalette := @P; +end; { TIndicator.GetPalette } + + +procedure TIndicator.SetState (AState : Word; Enable : Boolean); +begin + Inherited SetState (AState, Enable); + if AState = sfDragging then + DrawView; +end; { TIndicator.SetState } + + +procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean; + IsModified : Boolean; + IsWordWrap : Boolean); +begin + if (Location.X<>ALocation.X) or + (Location.Y<>ALocation.Y) or + (AutoIndent <> IsAutoIndent) or + (Modified <> IsModified) or + (WordWrap <> IsWordWrap) then + begin + Location := ALocation; + AutoIndent := IsAutoIndent; { Added provisions to show AutoIndent. } + Modified := IsModified; + WordWrap := IsWordWrap; { Added provisions to show WordWrap. } + DrawView; + end; +end; { TIndicator.SetValue } + + +{**************************************************************************** + TLineInfo +****************************************************************************} + +constructor TLineInfo.Init; +begin + MaxPos:=0; + Grow(1); +end; + + +destructor TLineInfo.Done; +begin + FreeMem(Info,MaxPos*sizeof(TLineInfoRec)); +end; + + +procedure TLineInfo.Grow(pos:Sw_word); +var + NewSize : Sw_word; + P : pointer; +begin + NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow)); + GetMem(P,NewSize*sizeof(TLineInfoRec)); + FillChar(P^,NewSize*sizeof(TLineInfoRec),0); + Move(Info^,P^,MaxPos*sizeof(TLineInfoRec)); + Freemem(Info,MaxPos*sizeof(TLineInfoRec)); + Info:=P; +end; + + +procedure TLineInfo.SetLen(pos,val:Sw_Word); +begin + if pos>=MaxPos then + Grow(Pos); + Info^[Pos].Len:=val +end; + + +procedure TLineInfo.SetAttr(pos,val:Sw_Word); +begin + if pos>=MaxPos then + Grow(Pos); + Info^[Pos].Attr:=val +end; + + +function TLineInfo.GetLen(pos:Sw_Word):Sw_Word; +begin + GetLen:=Info^[Pos].Len; +end; + + +function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word; +begin + GetAttr:=Info^[Pos].Attr; +end; + + + +{**************************************************************************** + TEditor +****************************************************************************} + +constructor TEditor.Init (var Bounds : TRect; + AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; ABufSize : Sw_Word); +var + Element : Byte; { Place_Marker array element to initialize array with. } +begin + Inherited Init (Bounds); + GrowMode := gfGrowHiX + gfGrowHiY; + Options := Options or ofSelectable; + Flags := EditorFlags; + EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast; + ShowCursor; + + HScrollBar := AHScrollBar; + VScrollBar := AVScrollBar; + + Indicator := AIndicator; + BufSize := ABufSize; + CanUndo := True; + InitBuffer; + + if assigned(Buffer) then + IsValid := True + else + begin + EditorDialog (edOutOfMemory, nil); + BufSize := 0; + end; + + SetBufLen (0); + + for Element := 1 to 10 do + Place_Marker[Element] := 0; + + Element := 1; + while Element <= 70 do + begin + if Element mod 5 = 0 then + Insert ('x', Tab_Settings, Element) + else + Insert (#32, Tab_Settings, Element); + Inc (Element); + end; + { Default Right_Margin value. Change it if you want another. } + Right_Margin := 76; + TabSize:=8; +end; { TEditor.Init } + + +constructor TEditor.Load (var S : Objects.TStream); +begin + Inherited Load (S); + GetPeerViewPtr (S, HScrollBar); + GetPeerViewPtr (S, VScrollBar); + GetPeerViewPtr (S, Indicator); + S.Read (BufSize, SizeOf (Sw_Word)); + S.Read (CanUndo, SizeOf (Boolean)); + S.Read (AutoIndent, SizeOf (AutoIndent)); + S.Read (Line_Number, SizeOf (Line_Number)); + S.Read (Place_Marker, SizeOf (Place_Marker)); + S.Read (Right_Margin, SizeOf (Right_Margin)); + S.Read (Tab_Settings, SizeOf (Tab_Settings)); + S.Read (Word_Wrap, SizeOf (Word_Wrap)); + InitBuffer; + if Assigned(Buffer) then + IsValid := True + else + begin + EditorDialog (edOutOfMemory, nil); + BufSize := 0; + end; + Lock; + SetBufLen (0); +end; { TEditor.Load } + + +destructor TEditor.Done; +begin + DoneBuffer; + Inherited Done; +end; { TEditor.Done } + + +function TEditor.BufChar(P: Sw_Word): Char; +begin + if P>=CurPtr then + inc(P,Gaplen); + BufChar:=Buffer^[P]; +end; + + +function TEditor.BufPtr(P: Sw_Word): Sw_Word; +begin + if P>=CurPtr then + BufPtr:=P+GapLen + else + BufPtr:=P; +end; + + +procedure TEditor.Center_Text (Select_Mode : Byte); +{ This procedure will center the current line of text. } +{ Centering is based on the current Right_Margin. } +{ If the Line_Length exceeds the Right_Margin, or the } +{ line is just a blank line, we exit and do nothing. } +VAR + Spaces : array [1..80] of Char; { Array to hold spaces we'll insert. } + Index : Byte; { Index into Spaces array. } + Line_Length : Sw_Integer; { Holds the length of the line. } + E,S : Sw_Word; { End of the current line. } +begin + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { If the line is blank (only a CR/LF on it) then do noting. } + if E = S then + Exit; + { Set CurPtr to start of line. Check if line begins with a space. } + { We must strip out any spaces from the beginning, or end of lines. } + { If line does not start with space, make sure line length does not } + { exceed the Right_Margin. If it does, then do nothing. } + SetCurPtr (S, Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if Buffer^[CurPtr] = #32 then + begin + { If the next word is greater than the end of line then do nothing. } + { If the line length is greater than Right_Margin then do nothing. } + { Otherwise, delete all spaces at the start of line. } + { Then reset end of line and put CurPtr at start of modified line. } + E := LineEnd (CurPtr); + if NextWord (CurPtr) > E then + Exit; + if E - NextWord (CurPtr) > Right_Margin then + Exit; + DeleteRange (CurPtr, NextWord (CurPtr), True); + E := LineEnd (CurPtr); + SetCurPtr (LineStart (CurPtr), Select_Mode); + end + else + if E - CurPtr > Right_Margin then + Exit; + { Now we determine the real length of the line. } + { Then we subtract the Line_Length from Right_Margin. } + { Dividing the result by two tells us how many spaces } + { must be inserted at start of line to center it. } + { When we're all done, set the CurPtr to end of line. } + Line_Length := E - CurPtr; + for Index := 1 to ((Right_Margin - Line_Length) shr 1) do + Spaces[Index] := #32; + InsertText (@Spaces, Index, False); + SetCurPtr (LineEnd (CurPtr), Select_Mode); +end; { TEditor.Center_Text } + + +procedure TEditor.ChangeBounds (var Bounds : TRect); +begin + SetBounds (Bounds); + Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X)); + Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y)); + Update (ufView); +end; { TEditor.ChangeBounds } + + +function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer; +VAR + Pos : Sw_Integer; +begin + Pos := 0; + while P < Target do + begin + if BufChar (P) = #9 then + Pos := Pos or 7; + Inc (Pos); + Inc (P); + end; + CharPos := Pos; +end; { TEditor.CharPos } + + +function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word; +VAR + Pos : Sw_Integer; +begin + Pos := 0; + while (Pos < Target) and (P < BufLen) and not(BufChar (P) in [#10,#13]) do + begin + if BufChar (P) = #9 then + Pos := Pos or 7; + Inc (Pos); + Inc (P); + end; + if Pos > Target then + Dec (P); + CharPtr := P; +end; { TEditor.CharPtr } + + +procedure TEditor.Check_For_Word_Wrap (Select_Mode : Byte; + Center_Cursor : Boolean); +{ This procedure checks if CurPos.X > Right_Margin. } +{ If it is, then we Do_Word_Wrap. Simple, eh? } +begin + if CurPos.X > Right_Margin then + Do_Word_Wrap (Select_Mode, Center_Cursor); +end; {Check_For_Word_Wrap} + + +function TEditor.ClipCopy : Boolean; +begin + ClipCopy := False; + if Assigned(Clipboard) and (Clipboard <> @Self) then + begin + ClipCopy := Clipboard^.InsertFrom (@Self); + Selecting := False; + Update (ufUpdate); + end; +end; { TEditor.ClipCopy } + + +procedure TEditor.ClipCut; +begin + if ClipCopy then + begin + Update_Place_Markers (0, + Self.SelEnd - Self.SelStart, + Self.SelStart, + Self.SelEnd); + DeleteSelect; + end; +end; { TEditor.ClipCut } + + +procedure TEditor.ClipPaste; +begin + if Assigned(Clipboard) and (Clipboard <> @Self) then + begin + { Do not allow paste operations that will exceed } + { the Right_Margin when Word_Wrap is active and } + { cursor is at EOL. } + if Word_Wrap and (CurPos.X > Right_Margin) then + begin + EditorDialog (edPasteNotPossible, nil); + Exit; + end; + { The editor will not copy selected text if the CurPtr } + { is not the same value as the SelStart. However, it } + { does return an InsCount. This may, or may not, be a } + { bug. We don't want to update the Place_Marker if } + { there's no text copied. } + if CurPtr = SelStart then + Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart, + 0, + Clipboard^.SelStart, + Clipboard^.SelEnd); + InsertFrom (Clipboard); + end; +end; { TEditor.ClipPaste } + + +procedure TEditor.ConvertEvent (var Event : Drivers.TEvent); +VAR + ShiftState : Byte; + Key : Word; +begin + ShiftState:=GetShiftState; + if Event.What = evKeyDown then + begin + if (ShiftState and $03 <> 0) + and (Event.ScanCode >= $47) + and (Event.ScanCode <= $51) then + Event.CharCode := #0; + Key := Event.KeyCode; + if KeyState <> 0 then + begin + if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then + Inc (Key, $40); + if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then + Dec (Key, $20); + end; + Key := ScanKeyMap (KeyMap[KeyState], Key); + KeyState := 0; + if Key <> 0 then + if Hi (Key) = $FF then + begin + KeyState := Lo (Key); + ClearEvent (Event); + end + else + begin + Event.What := evCommand; + Event.Command := Key; + end; + end; +end; { TEditor.ConvertEvent } + + +function TEditor.CursorVisible : Boolean; +begin + CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y); +end; { TEditor.CursorVisible } + + +procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean); +begin + { This will update Place_Marker for all deletions. } + { EXCEPT the Remove_EOL_Spaces deletion. } + Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr); + if HasSelection and DelSelect then + DeleteSelect + else + begin + SetSelect (CurPtr, EndPtr, True); + DeleteSelect; + SetSelect (StartPtr, CurPtr, False); + DeleteSelect; + end; +end; { TEditor.DeleteRange } + + +procedure TEditor.DeleteSelect; +begin + InsertText (nil, 0, False); +end; { TEditor.DeleteSelect } + + +procedure TEditor.DoneBuffer; +begin + if assigned(Buffer) then + begin + FreeMem (Buffer, BufSize); + Buffer := nil; + end; +end; { TEditor.DoneBuffer } + + +procedure TEditor.DoSearchReplace; +VAR + I : Sw_Word; + C : Objects.TPoint; +begin + repeat + I := cmCancel; + if not Search (FindStr, Flags) then + begin + if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then + EditorDialog (edSearchFailed, nil) + end + else + if Flags and efDoReplace <> 0 then + begin + I := cmYes; + if Flags and efPromptOnReplace <> 0 then + begin + MakeGlobal (Cursor, C); + I := EditorDialog (edReplacePrompt, Pointer(@C)); + end; + if I = cmYes then + begin + { If Word_Wrap is active and we are at EOL } + { disallow replace by bringing up a dialog } + { stating that replace is not possible. } + if Word_Wrap and + ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then + EditorDialog (edReplaceNotPossible, nil) + else + begin + Lock; + Search_Replace := True; + if length (ReplaceStr) < length (FindStr) then + Update_Place_Markers (0, + Length (FindStr) - Length (ReplaceStr), + CurPtr - Length (FindStr) + Length (ReplaceStr), + CurPtr) + else + if length (ReplaceStr) > length (FindStr) then + Update_Place_Markers (Length (ReplaceStr) - Length (FindStr), + 0, + CurPtr, + CurPtr + (Length (ReplaceStr) - Length (FindStr))); + InsertText (@ReplaceStr[1], Length (ReplaceStr), False); + Search_Replace := False; + TrackCursor (False); + Unlock; + end; + end; + end; + until (I = cmCancel) or (Flags and efReplaceAll = 0); +end; { TEditor.DoSearchReplace } + + +procedure TEditor.DoUpdate; +begin + if UpdateFlags <> 0 then + begin + SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y); + if UpdateFlags and ufView <> 0 then + DrawView + else + if UpdateFlags and ufLine <> 0 then + DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr)); + if assigned(HScrollBar) then + HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1); + if assigned(VScrollBar) then + VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1); + if assigned(Indicator) then + Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap); + if State and sfActive <> 0 then + UpdateCommands; + UpdateFlags := 0; + end; +end; { TEditor.DoUpdate } + + +function TEditor.Do_Word_Wrap (Select_Mode : Byte; + Center_Cursor : Boolean) : Boolean; +{ This procedure does the actual wordwrap. It always assumes the CurPtr } +{ is at Right_Margin + 1. It makes several tests for special conditions } +{ and processes those first. If they all fail, it does a normal wrap. } +VAR + A : Sw_Word; { Distance between line start and first word on line. } + C : Sw_Word; { Current pointer when we come into procedure. } + L : Sw_Word; { BufLen when we come into procedure. } + P : Sw_Word; { Position of pointer at any given moment. } + S : Sw_Word; { Start of a line. } +begin + Do_Word_Wrap := False; + Select_Mode := 0; + if BufLen >= (BufSize - 1) then + exit; + C := CurPtr; + L := BufLen; + S := LineStart (CurPtr); + { If first character in the line is a space and autoindent mode is on } + { then we check to see if NextWord(S) exceeds the CurPtr. If it does, } + { we set CurPtr as the AutoIndent marker. If it doesn't, we will set } + { NextWord(S) as the AutoIndent marker. If neither, we set it to S. } + if AutoIndent and (Buffer^[S] = ' ') then + begin + if NextWord (S) > CurPtr then + A := CurPtr + else + A := NextWord (S); + end + else + A := NextWord (S); + { Though NewLine will remove EOL spaces, we do it here too. } + { This catches the instance where a user may try to space } + { completely across the line, in which case CurPtr.X = 0. } + Remove_EOL_Spaces (Select_Mode); + if CurPos.X = 0 then + begin + NewLine (Select_Mode); + Do_Word_Wrap := True; + Exit; + end; + { At this point we have one of five situations: } + { } + { 1) AutoIndent is on and this line is all spaces before CurPtr. } + { 2) AutoIndent is off and this line is all spaces before CurPtr. } + { 3) AutoIndent is on and this line is continuous characters before CurPtr. } + { 4) AutoIndent is off and this line is continuous characters before CurPtr. } + { 5) This is just a normal line of text. } + { } + { Conditions 1 through 4 have to be taken into account before condition 5. } + { First, we see if there are all spaces and/or all characters. } + { Then we determine which one it really is. Finally, we take } + { a course of action based on the state of AutoIndent. } + if PrevWord (CurPtr) <= S then + begin + P := CurPtr - 1; + while ((Buffer^[P] <> ' ') and (P > S)) do + Dec (P); + { We found NO SPACES. Conditions 4 and 5 are treated the same. } + { We can NOT do word wrap and put up a dialog box stating such. } + { Delete character just entered so we don't exceed Right_Margin. } + if P = S then + begin + EditorDialog (edWrapNotPossible, nil); + DeleteRange (PrevChar (CurPtr), CurPtr, True); + Exit; + end + else + begin + { There are spaces. Now find out if they are all spaces. } + { If so, see if AutoIndent is on. If it is, turn it off, } + { do a NewLine, and turn it back on. Otherwise, just do } + { the NewLine. We go through all of these gyrations for } + { AutoIndent. Being way out here with a preceding line } + { of spaces and wrapping with AutoIndent on is real dumb! } + { However, the user expects something. The wrap will NOT } + { autoindent, but they had no business being here anyway! } + P := CurPtr - 1; + while ((Buffer^[P] = ' ') and (P > S)) do + Dec (P); + if P = S then + begin + if Autoindent then + begin + AutoIndent := False; + NewLine (Select_Mode); + AutoIndent := True; + end + else + NewLine (Select_Mode); + end; { AutoIndent } + end; { P = S for spaces } + end { P = S for no spaces } + else { PrevWord (CurPtr) <= S } + begin + { Hooray! We actually had a plain old line of text to wrap! } + { Regardless if we are pushing out a line beyond the Right_Margin, } + { or at the end of a line itself, the following will determine } + { exactly where to do the wrap and re-set the cursor accordingly. } + { However, if P = A then we can't wrap. Show dialog and exit. } + P := CurPtr; + while P - S > Right_Margin do + P := PrevWord (P); + if (P = A) then + begin + EditorDialog (edReformNotPossible, nil); + SetCurPtr (P, Select_Mode); + Exit; + end; + SetCurPtr (P, Select_Mode); + NewLine (Select_Mode); + end; { PrevWord (CurPtr <= S } + { Track the cursor here (it is at CurPos.X = 0) so the view } + { will redraw itself at column 0. This eliminates having it } + { redraw starting at the current cursor and not being able } + { to see text before the cursor. Of course, we also end up } + { redrawing the view twice, here and back in HandleEvent. } + { } + { Reposition cursor so user can pick up where they left off. } + TrackCursor (Center_Cursor); + SetCurPtr (C - (L - BufLen), Select_Mode); + Do_Word_Wrap := True; +end; { TEditor.Do_Word_Wrap } + + +procedure TEditor.Draw; +begin + if DrawLine <> Delta.Y then + begin + DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine); + DrawLine := Delta.Y; + end; + DrawLines (0, Size.Y, DrawPtr); +end; { TEditor.Draw } + + +procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word); +VAR + Color : Word; + B : array[0..MaxLineLength - 1] of Sw_Word; +begin + Color := GetColor ($0201); + while Count > 0 do + begin + FormatLine (B, LinePtr, Delta.X + Size.X, Color); + WriteBuf (0, Y, Size.X, 1, B[Delta.X]); + LinePtr := NextLine (LinePtr); + Inc (Y); + Dec (Count); + end; +end; { TEditor.DrawLines } + + +procedure TEditor.Find; +VAR + FindRec : TFindDialogRec; +begin + with FindRec do + begin + Find := FindStr; + Options := Flags; + if EditorDialog (edFind, @FindRec) <> cmCancel then + begin + FindStr := Find; + Flags := Options and not efDoReplace; + DoSearchReplace; + end; + end; +end; { TEditor.Find } + + +procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word; + Width : Sw_Integer; + Colors : Word); +var + outptr : pword; + outcnt, + idxpos : Sw_Word; + attr : Word; + + procedure FillSpace(i:Sw_Word); + var + w : word; + begin + inc(OutCnt,i); + w:=32 or attr; + while (i>0) do + begin + OutPtr^:=w; + inc(OutPtr); + dec(i); + end; + end; + + function FormatUntil(endpos:Sw_word):boolean; + var + p : pchar; + begin + FormatUntil:=false; + p:=pchar(Buffer)+idxpos; + while endpos>idxpos do + begin + if OutCnt>=Width then + exit; + case p^ of + #9 : + FillSpace(Tabsize-(outcnt mod Tabsize)); + #10,#13 : + begin + FillSpace(Width-OutCnt); + FormatUntil:=true; + exit; + end; + else + begin + inc(OutCnt); + OutPtr^:=ord(p^) or attr; + inc(OutPtr); + end; + end; { case } + inc(p); + inc(idxpos); + end; + end; + +begin + OutCnt:=0; + OutPtr:=@DrawBuf; + idxPos:=LinePtr; + attr:=lo(Colors) shl 8; + if FormatUntil(SelStart) then + exit; + attr:=hi(Colors) shl 8; + if FormatUntil(CurPtr) then + exit; + inc(idxPos,GapLen); + if FormatUntil(SelEnd+GapLen) then + exit; + attr:=lo(Colors) shl 8; + if FormatUntil(BufSize) then + exit; +{ fill up until width } + FillSpace(Width-OutCnt); +end; {TEditor.FormatLine} + + +function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word; +begin + MakeLocal (Mouse, Mouse); + Mouse.X := Max (0, Min (Mouse.X, Size.X - 1)); + Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1)); + GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine), + Mouse.X + Delta.X); +end; { TEditor.GetMousePtr } + + +function TEditor.GetPalette : PPalette; +CONST + P : String[Length (CEditor)] = CEditor; +begin + GetPalette := @P; +end; { TEditor.GetPalette } + + +procedure TEditor.HandleEvent (var Event : Drivers.TEvent); +VAR + ShiftState : Byte; + CenterCursor : Boolean; + SelectMode : Byte; + D : Objects.TPoint; + Mouse : Objects.TPoint; + + function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean; + begin + CheckScrollBar := FALSE; + if (Event.InfoPtr = P) and (P^.Value <> D) then + begin + D := P^.Value; + Update (ufView); + CheckScrollBar := TRUE; + end; + end; {CheckScrollBar} + +begin + Inherited HandleEvent (Event); + ConvertEvent (Event); + CenterCursor := not CursorVisible; + SelectMode := 0; + ShiftState:=GetShiftState; + if Selecting or (ShiftState and $03 <> 0) then + SelectMode := smExtend; + case Event.What of + Drivers.evMouseDown: + begin + if Event.Double then + SelectMode := SelectMode or smDouble; + repeat + Lock; + if Event.What = evMouseAuto then + begin + MakeLocal (Event.Where, Mouse); + D := Delta; + if Mouse.X < 0 then + Dec (D.X); + if Mouse.X >= Size.X then + Inc (D.X); + if Mouse.Y < 0 then + Dec (D.Y); + if Mouse.Y >= Size.Y then + Inc (D.Y); + ScrollTo (D.X, D.Y); + end; + SetCurPtr (GetMousePtr (Event.Where), SelectMode); + SelectMode := SelectMode or smExtend; + Unlock; + until not MouseEvent (Event, evMouseMove + evMouseAuto); + end; { Drivers.evMouseDown } + + Drivers.evKeyDown: + case Event.CharCode of + #32..#255: + begin + Lock; + if Overwrite and not HasSelection then + if CurPtr <> LineEnd (CurPtr) then + SelEnd := NextChar (CurPtr); + InsertText (@Event.CharCode, 1, False); + if Word_Wrap then + Check_For_Word_Wrap (SelectMode, CenterCursor); + TrackCursor (CenterCursor); + Unlock; + end; + + else + Exit; + end; { Drivers.evKeyDown } + + Drivers.evCommand: + case Event.Command of + cmFind : Find; + cmReplace : Replace; + cmSearchAgain : DoSearchReplace; + else + begin + Lock; + case Event.Command of + cmCut : ClipCut; + cmCopy : ClipCopy; + cmPaste : ClipPaste; + cmUndo : Undo; + cmClear : DeleteSelect; + cmCharLeft : SetCurPtr (PrevChar (CurPtr), SelectMode); + cmCharRight : SetCurPtr (NextChar (CurPtr), SelectMode); + cmWordLeft : SetCurPtr (PrevWord (CurPtr), SelectMode); + cmWordRight : SetCurPtr (NextWord (CurPtr), SelectMode); + cmLineStart : SetCurPtr (LineStart (CurPtr), SelectMode); + cmLineEnd : SetCurPtr (LineEnd (CurPtr), SelectMode); + cmLineUp : SetCurPtr (LineMove (CurPtr, -1), SelectMode); + cmLineDown : SetCurPtr (LineMove (CurPtr, 1), SelectMode); + cmPageUp : SetCurPtr (LineMove (CurPtr, - (Size.Y - 1)), SelectMode); + cmPageDown : SetCurPtr (LineMove (CurPtr, Size.Y - 1), SelectMode); + cmTextStart : SetCurPtr (0, SelectMode); + cmTextEnd : SetCurPtr (BufLen, SelectMode); + cmNewLine : NewLine (SelectMode); + cmBackSpace : DeleteRange (PrevChar (CurPtr), CurPtr, True); + cmDelChar : DeleteRange (CurPtr, NextChar (CurPtr), True); + cmDelWord : DeleteRange (CurPtr, NextWord (CurPtr), False); + cmDelStart : DeleteRange (LineStart (CurPtr), CurPtr, False); + cmDelEnd : DeleteRange (CurPtr, LineEnd (CurPtr), False); + cmDelLine : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False); + cmInsMode : ToggleInsMode; + cmStartSelect : StartSelect; + cmHideSelect : HideSelect; + cmIndentMode : begin + AutoIndent := not AutoIndent; + Update (ufStats); + end; { Added provision to update TIndicator if ^QI pressed. } + cmCenterText : Center_Text (SelectMode); + cmEndPage : SetCurPtr (LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode); + cmHomePage : SetCurPtr (LineMove (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode); + cmInsertLine : Insert_Line (SelectMode); + cmJumpLine : Jump_To_Line (SelectMode); + cmReformDoc : Reformat_Document (SelectMode, CenterCursor); + cmReformPara : Reformat_Paragraph (SelectMode, CenterCursor); + cmRightMargin : Set_Right_Margin; + cmScrollDown : Scroll_Down; + cmScrollUp : Scroll_Up; + cmSelectWord : Select_Word; + cmSetTabs : Set_Tabs; + cmTabKey : Tab_Key (SelectMode); + cmWordWrap : begin + Word_Wrap := not Word_Wrap; + Update (ufStats); + end; { Added provision to update TIndicator if ^OW pressed. } + cmSetMark0 : Set_Place_Marker (10); + cmSetMark1 : Set_Place_Marker (1); + cmSetMark2 : Set_Place_Marker (2); + cmSetMark3 : Set_Place_Marker (3); + cmSetMark4 : Set_Place_Marker (4); + cmSetMark5 : Set_Place_Marker (5); + cmSetMark6 : Set_Place_Marker (6); + cmSetMark7 : Set_Place_Marker (7); + cmSetMark8 : Set_Place_Marker (8); + cmSetMark9 : Set_Place_Marker (9); + cmJumpMark0 : Jump_Place_Marker (10, SelectMode); + cmJumpMark1 : Jump_Place_Marker (1, SelectMode); + cmJumpMark2 : Jump_Place_Marker (2, SelectMode); + cmJumpMark3 : Jump_Place_Marker (3, SelectMode); + cmJumpMark4 : Jump_Place_Marker (4, SelectMode); + cmJumpMark5 : Jump_Place_Marker (5, SelectMode); + cmJumpMark6 : Jump_Place_Marker (6, SelectMode); + cmJumpMark7 : Jump_Place_Marker (7, SelectMode); + cmJumpMark8 : Jump_Place_Marker (8, SelectMode); + cmJumpMark9 : Jump_Place_Marker (9, SelectMode); + else + Unlock; + Exit; + end; { Event.Command (Inner) } + TrackCursor (CenterCursor); + { If the user presses any key except cmNewline or cmBackspace } + { we need to check if the file has been modified yet. There } + { can be no spaces at the end of a line, or wordwrap doesn't } + { work properly. We don't want to do this if the file hasn't } + { been modified because the user could be bringing in an ASCII } + { file from an editor that allows spaces at the EOL. If we } + { took them out in that scenario the "M" would appear on the } + { TIndicator line and the user would get upset or confused. } + if (Event.Command <> cmNewLine) and + (Event.Command <> cmBackSpace) and + (Event.Command <> cmTabKey) and + Modified then + Remove_EOL_Spaces (SelectMode); + Unlock; + end; { Event.Command (Outer) } + end; { Drivers.evCommand } + + Drivers.evBroadcast: + case Event.Command of + cmScrollBarChanged: + if (Event.InfoPtr = HScrollBar) or + (Event.InfoPtr = VScrollBar) then + begin + CheckScrollBar (HScrollBar, Delta.X); + CheckScrollBar (VScrollBar, Delta.Y); + end + else + exit; + else + Exit; + end; { Drivers.evBroadcast } + + end; + ClearEvent (Event); +end; { TEditor.HandleEvent } + + +function TEditor.HasSelection : Boolean; +begin + HasSelection := SelStart <> SelEnd; +end; { TEditor.HasSelection } + + +procedure TEditor.HideSelect; +begin + Selecting := False; + SetSelect (CurPtr, CurPtr, False); +end; { TEditor.HideSelect } + + +procedure TEditor.InitBuffer; +begin + Buffer := MemAlloc (BufSize); +end; { TEditor.InitBuffer } + + +function TEditor.InsertBuffer (var P : PEditBuffer; + Offset, Length : Sw_Word; + AllowUndo, SelectText : Boolean) : Boolean; +VAR + SelLen : Sw_Word; + DelLen : Sw_Word; + SelLines : Sw_Word; + Lines : Sw_Word; + NewSize : Longint; +begin + InsertBuffer := True; + Selecting := False; + SelLen := SelEnd - SelStart; + if (SelLen = 0) and (Length = 0) then + Exit; + DelLen := 0; + if AllowUndo then + if CurPtr = SelStart then + DelLen := SelLen + else + if SelLen > InsCount then + DelLen := SelLen - InsCount; + NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length; + if NewSize > BufLen + DelCount then + if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then + begin + EditorDialog (edOutOfMemory, nil); + InsertBuffer := False; + SelEnd := SelStart; + Exit; + end; + SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen); + if CurPtr = SelEnd then + begin + if AllowUndo then + begin + if DelLen > 0 then + Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen); + Dec (InsCount, SelLen - DelLen); + end; + CurPtr := SelStart; + Dec (CurPos.Y, SelLines); + end; + if Delta.Y > CurPos.Y then + begin + Dec (Delta.Y, SelLines); + if Delta.Y < CurPos.Y then + Delta.Y := CurPos.Y; + end; + if Length > 0 then + Move (P^[Offset], Buffer^[CurPtr], Length); + Lines := CountLines (Buffer^[CurPtr], Length); + Inc (CurPtr, Length); + Inc (CurPos.Y, Lines); + DrawLine := CurPos.Y; + DrawPtr := LineStart (CurPtr); + CurPos.X := CharPos (DrawPtr, CurPtr); + if not SelectText then + SelStart := CurPtr; + SelEnd := CurPtr; + if Length>Sellen then + begin + Inc (BufLen, Length - SelLen); + Dec (GapLen, Length - SelLen); + end + else + begin + Dec (BufLen, Sellen - Length); + Inc (GapLen, Sellen - Length); + end; + if AllowUndo then + begin + Inc (DelCount, DelLen); + Inc (InsCount, Length); + end; + Inc (Limit.Y, Lines - SelLines); + Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y)); + if not IsClipboard then + Modified := True; + SetBufSize (BufLen + DelCount); + if (SelLines = 0) and (Lines = 0) then + Update (ufLine) + else + Update (ufView); +end; { TEditor.InsertBuffer } + + +function TEditor.InsertFrom (Editor : PEditor) : Boolean; +begin + InsertFrom := InsertBuffer (Editor^.Buffer, + Editor^.BufPtr (Editor^.SelStart), + Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard); +end; { TEditor.InsertFrom } + + +procedure TEditor.Insert_Line (Select_Mode : Byte); +{ This procedure inserts a newline at the current cursor position } +{ if a ^N is pressed. Unlike cmNewLine, the cursor will return } +{ to its original position. If the cursor was at the end of a } +{ line, and its spaces were removed, the cursor returns to the } +{ end of the line instead. } +begin + NewLine (Select_Mode); + SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode); +end; { TEditor.Insert_Line } + + +function TEditor.InsertText (Text : Pointer; + Length : Sw_Word; + SelectText : Boolean) : Boolean; +begin + if assigned(Text) and not Search_Replace then + Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd); + InsertText := InsertBuffer (PEditBuffer (Text), + 0, Length, CanUndo, SelectText); +end; { TEditor.InsertText } + + +function TEditor.IsClipboard : Boolean; +begin + IsClipboard := Clipboard = @Self; +end; { TEditor.IsClipboard } + + +procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte); +{ This procedure jumps to a place marker if ^Q# is pressed. } +{ We don't go anywhere if Place_Marker[Element] is not zero. } +begin + if (not IsClipboard) and (Place_Marker[Element] <> 0) then + SetCurPtr (Place_Marker[Element], Select_Mode); +end; { TEditor.Jump_Place_Marker } + + +procedure TEditor.Jump_To_Line (Select_Mode : Byte); +{ This function brings up a dialog box that allows } +{ the user to select a line number to jump to. } +VAR + Code : Integer; { Used for Val conversion. } + Temp_Value : Longint; { Holds converted dialog value. } +begin + if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then + begin + { Convert the Line_Number string to an interger. } + { Put it into Temp_Value. If the number is not } + { in the range 1..9999 abort. If the number is } + { our current Y position, abort. Otherwise, } + { go to top of document, and jump to the line. } + { There are faster methods. This one's easy. } + { Note that CurPos.Y is always 1 less than what } + { the TIndicator line says. } + val (Line_Number, Temp_Value, Code); + if (Temp_Value < 1) or (Temp_Value > 9999999) then + Exit; + if Temp_Value = CurPos.Y + 1 then + Exit; + SetCurPtr (0, Select_Mode); + SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode); + end; +end; {TEditor.Jump_To_Line} + + +function TEditor.LineEnd (P : Sw_Word) : Sw_Word; +var + start, + i : Sw_word; + pc : pchar; +begin + if P0) do + begin + if pc^ in [#10,#13] then + begin + LineEnd:=pc-pchar(Buffer); + exit; + end; + inc(pc); + dec(i); + end; + start:=CurPtr; + end + else + start:=P; + i:=BufLen-Start; + pc:=pchar(Buffer)+GapLen+start; + while (i>0) do + begin + if pc^ in [#10,#13] then + begin + LineEnd:=pc-(pchar(Buffer)+Gaplen); + exit; + end; + inc(pc); + dec(i); + end; + LineEnd:=pc-(pchar(Buffer)+Gaplen); +end; { TEditor.LineEnd } + + +function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word; +VAR + Pos : Sw_Integer; + I : Sw_Word; +begin + I := P; + P := LineStart (P); + Pos := CharPos (P, I); + while Count <> 0 do + begin + I := P; + if Count < 0 then + begin + P := PrevLine (P); + Inc (Count); + end + else + begin + P := NextLine (P); + Dec (Count); + end; + end; + if P <> I then + P := CharPtr (P, Pos); + LineMove := P; +end; { TEditor.LineMove } + + +function TEditor.LineStart (P : Sw_Word) : Sw_Word; +var + i : Sw_word; + start,pc : pchar; + oc : char; +begin + if P>CurPtr then + begin + start:=pchar(Buffer)+GapLen; + pc:=start; + i:=P-CurPtr; + dec(pc); + while (i>0) do + begin + if pc^ in [#10,#13] then + break; + dec(pc); + dec(i); + end; + end + else + i:=0; + if i=0 then + begin + start:=pchar(Buffer); + i:=P; + pc:=start+p; + dec(pc); + while (i>0) do + begin + if pc^ in [#10,#13] then + break; + dec(pc); + dec(i); + end; + if i=0 then + begin + LineStart:=0; + exit; + end; + end; + oc:=pc^; + LineStart:=pc-start+1; +end; { TEditor.LineStart } + + +function TEditor.LineNr (P : Sw_Word) : Sw_Word; +var + pc,endp : pchar; + lines : sw_word; +begin + endp:=pchar(Buffer)+BufPtr(P); + pc:=pchar(Buffer); + lines:=0; + while (pc=endp) then + break; + end; + end; + inc(pc); + end; + LineNr:=Lines; +end; + + +procedure TEditor.Lock; +begin + Inc (LockCount); +end; { TEditor.Lock } + + +function TEditor.NewLine (Select_Mode : Byte) : Boolean; +VAR + I : Sw_Word; { Used to track spaces for AutoIndent. } + P : Sw_Word; { Position of Cursor when we arrive and after Newline. } +begin + P := LineStart (CurPtr); + I := P; + { The first thing we do is remove any End Of Line spaces. } + { Then we check to see how many spaces are on beginning } + { of a line. We need this check to add them after CR/LF } + { if AutoIndenting. Last of all we insert spaces required } + { for the AutoIndenting, if it was on. } + Remove_EOL_Spaces (Select_Mode); + while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do + Inc (I); + if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then + exit; + if AutoIndent then + InsertText (@Buffer^[P], I - P, False); + { Remember where the CurPtr is at this moment. } + { Remember the length of the buffer at the moment. } + { Go to the previous line and remove EOL spaces. } + { Once removed, re-set the cursor to where we were } + { minus any spaces that might have been removed. } + I := BufLen; + P := CurPtr; + SetCurPtr (LineMove (CurPtr, - 1), Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if I - BufLen <> 0 then + SetCurPtr (P - (I - BufLen), Select_Mode) + else + SetCurPtr (P, Select_Mode); + NewLine:=true; +end; { TEditor.NewLine } + + +function TEditor.NextChar (P : Sw_Word) : Sw_Word; +var + pc : pchar; +begin + if P<>BufLen then + begin + inc(P); + if P<>BufLen then + begin + pc:=pchar(Buffer); + if P>=CurPtr then + inc(pc,GapLen); + inc(pc,P-1); + if ord(pc^)+ord((pc+1)^)=23 then + inc(p); + end; + end; + NextChar:=P; +end; { TEditor.NextChar } + + +function TEditor.NextLine (P : Sw_Word) : Sw_Word; +begin + NextLine := NextChar (LineEnd (P)); +end; { TEditor.NextLine } + + +function TEditor.NextWord (P : Sw_Word) : Sw_Word; +begin + { skip word } + while (P < BufLen) and (BufChar (P) in WordChars) do + P := NextChar (P); + { skip spaces } + while (P < BufLen) and not (BufChar (P) in WordChars) do + P := NextChar (P); + NextWord := P; +end; { TEditor.NextWord } + + +function TEditor.PrevChar (P : Sw_Word) : Sw_Word; +var + pc : pchar; +begin + if p<>0 then + begin + dec(p); + if p<>0 then + begin + pc:=pchar(Buffer); + if P>=CurPtr then + inc(pc,GapLen); + inc(pc,P-1); + if ord(pc^)+ord((pc+1)^)=23 then + dec(p); + end; + end; + PrevChar:=P; +end; { TEditor.PrevChar } + + +function TEditor.PrevLine (P : Sw_Word) : Sw_Word; +begin + PrevLine := LineStart (PrevChar (P)); +end; { TEditor.PrevLine } + + +function TEditor.PrevWord (P : Sw_Word) : Sw_Word; +begin + { skip spaces } + while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do + P := PrevChar (P); + { skip word } + while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do + P := PrevChar (P); + PrevWord := P; +end; { TEditor.PrevWord } + + +procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean); +{ This procedure will do a reformat of the entire document, or just } +{ from the current line to the end of the document, if ^QU is pressed. } +{ It simply brings up the correct dialog box, and then calls the } +{ TEditor.Reformat_Paragraph procedure to do the actual reformatting. } +CONST + efCurrentLine = $0000; { Radio button #1 selection for dialog box. } + efWholeDocument = $0001; { Radio button #2 selection for dialog box. } +VAR + Reformat_Options : Word; { Holds the dialog options for reformatting. } +begin + { Check if Word_Wrap is toggled on. If NOT on, check if programmer } + { allows reformatting of document and if not show user dialog that } + { says reformatting is not permissable. } + if not Word_Wrap then + begin + if not Allow_Reformat then + begin + EditorDialog (edReformatNotAllowed, nil); + Exit; + end; + Word_Wrap := True; + Update (ufStats); + end; + { Default radio button option to 1st one. Bring up dialog box. } + Reformat_Options := efCurrentLine; + if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then + begin + { If the option to reformat the whole document was selected } + { we need to go back to start of document. Otherwise we stay } + { on the current line. Call Reformat_Paragraph until we get } + { to the end of the document to do the reformatting. } + if Reformat_Options and efWholeDocument <> 0 then + SetCurPtr (0, Select_Mode); + Unlock; + repeat + Lock; + if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then + Exit; + TrackCursor (False); + Unlock; + until CurPtr = BufLen; + end; +end; { TEditor.Reformat_Document } + + +function TEditor.Reformat_Paragraph (Select_Mode : Byte; + Center_Cursor : Boolean) : Boolean; +{ This procedure will do a reformat of the current paragraph if ^B pressed. } +{ The feature works regardless if wordrap is on or off. It also supports } +{ the AutoIndent feature. Reformat is not possible if the CurPos exceeds } +{ the Right_Margin. Right_Margin is where the EOL is considered to be. } +CONST + Space : array [1..2] of Char = #32#32; +VAR + C : Sw_Word; { Position of CurPtr when we come into procedure. } + E : Sw_Word; { End of a line. } + S : Sw_Word; { Start of a line. } +begin + Reformat_Paragraph := False; + { Check if Word_Wrap is toggled on. If NOT on, check if programmer } + { allows reformatting of paragraph and if not show user dialog that } + { says reformatting is not permissable. } + if not Word_Wrap then + begin + if not Allow_Reformat then + begin + EditorDialog (edReformatNotAllowed, nil); + Exit; + end; + Word_Wrap := True; + Update (ufStats); + end; + C := CurPtr; + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { Reformat possible only if current line is NOT blank! } + if E <> S then + begin + { Reformat is NOT possible if the first word } + { on the line is beyond the Right_Margin. } + S := LineStart (CurPtr); + if NextWord (S) - S >= Right_Margin - 1 then + begin + EditorDialog (edReformNotPossible, nil); + Exit; + end; + { First objective is to find the first blank line } + { after this paragraph so we know when to stop. } + { That could be the end of the document. } + Repeat + SetCurPtr (LineMove (CurPtr, 1), Select_Mode); + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + BlankLine := E; + until ((CurPtr = BufLen) or (E = S)); + SetCurPtr (C, Select_Mode); + repeat + { Set CurPtr to LineEnd and remove the EOL spaces. } + { Pull up the next line and remove its EOL space. } + { First make sure the next line is not BlankLine! } + { Insert spaces as required between the two lines. } + SetCurPtr (LineEnd (CurPtr), Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if CurPtr <> Blankline - 2 then + DeleteRange (CurPtr, Nextword (CurPtr), True); + Remove_EOL_Spaces (Select_Mode); + case Buffer^[CurPtr-1] of + '!' : InsertText (@Space, 2, False); + '.' : InsertText (@Space, 2, False); + ':' : InsertText (@Space, 2, False); + '?' : InsertText (@Space, 2, False); + else + InsertText (@Space, 1, False); + end; + { Reset CurPtr to EOL. While line length is > Right_Margin } + { go Do_Word_Wrap. If wordrap failed, exit routine. } + SetCurPtr (LineEnd (CurPtr), Select_Mode); + while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do + if not Do_Word_Wrap (Select_Mode, Center_Cursor) then + Exit; + { If LineEnd - LineStart > Right_Margin then set CurPtr } + { to Right_Margin on current line. Otherwise we set the } + { CurPtr to LineEnd. This gyration sets up the conditions } + { to test for time of loop exit. } + if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then + SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode) + else + SetCurPtr (LineEnd (CurPtr), Select_Mode); + until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2)); + end; + { If not at the end of the document reset CurPtr to start of next line. } + { This should be a blank line between paragraphs. } + if CurPtr < BufLen then + SetCurPtr (LineMove (CurPtr, 1), Select_Mode); + Reformat_Paragraph := True; +end; { TEditor.Reformat_Paragraph } + + +procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte); +{ This procedure tests to see if there are consecutive spaces } +{ at the end of a line (EOL). If so, we delete all spaces } +{ after the last non-space character to the end of line. } +{ We then reset the CurPtr to where we ended up at. } +VAR + C : Sw_Word; { Current pointer when we come into procedure. } + E : Sw_Word; { End of line. } + P : Sw_Word; { Position of pointer at any given moment. } + S : Sw_Word; { Start of a line. } +begin + C := CurPtr; + E := LineEnd (CurPtr); + P := E; + S := LineStart (CurPtr); + { Start at the end of a line and move towards the start. } + { Find first non-space character in that direction. } + while (P > S) and (BufChar (PrevChar (P)) = #32) do + P := PrevChar (P); + { If we found any spaces then delete them. } + if P < E then + begin + SetSelect (P, E, True); + DeleteSelect; + Update_Place_Markers (0, E - P, P, E); + end; + { If C, our pointer when we came into this procedure, } + { is less than the CurPtr then reset CurPtr to C so } + { cursor is where we started. Otherwise, set it to } + { the new CurPtr, for we have deleted characters. } + if C < CurPtr then + SetCurPtr (C, Select_Mode) + else + SetCurPtr (CurPtr, Select_Mode); +end; { TEditor.Remove_EOL_Spaces } + + +procedure TEditor.Replace; +VAR + ReplaceRec : TReplaceDialogRec; +begin + with ReplaceRec do + begin + Find := FindStr; + Replace := ReplaceStr; + Options := Flags; + if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then + begin + FindStr := Find; + ReplaceStr := Replace; + Flags := Options or efDoReplace; + DoSearchReplace; + end; + end; +end; { TEditor.Replace } + + +procedure TEditor.Scroll_Down; +{ This procedure will scroll the screen up, and always keep } +{ the cursor on the CurPos.Y position, but not necessarily on } +{ the CurPos.X. If CurPos.Y scrolls off the screen, the cursor } +{ will stay in the upper left corner of the screen. This will } +{ simulate the same process in the IDE. The CurPos.X coordinate } +{ only messes up if we are on long lines and we then encounter } +{ a shorter or blank line beneath the current one as we scroll. } +{ In that case, it goes to the end of the new line. } +VAR + C : Sw_Word; { Position of CurPtr when we enter procedure. } + P : Sw_Word; { Position of CurPtr at any given time. } + W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). } +begin + { Remember current cursor position. Remember current CurPos.Y position. } + { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will } + { go to the bottom of the current screen. Reset the cursor to this new } + { position and then send FALSE to TrackCursor so we fool it into } + { incrementing Delta.Y by only +1. If we didn't do this it would try } + { to center the cursor on the screen by fiddling with Delta.Y. } + C := CurPtr; + W.X := CurPos.Y; + P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y); + SetCurPtr (P, 0); + TrackCursor (False); + { Now remember where the new CurPos.Y is. See if distance between new } + { CurPos.Y and old CurPos.Y are greater than the current screen size. } + { If they are, we need to move cursor position itself down by one. } + { Otherwise, send the cursor back to our original CurPtr. } + W.Y := CurPos.Y; + if W.Y - W.X > Size.Y - 1 then + SetCurPtr (LineMove (C, 1), 0) + else + SetCurPtr (C, 0); +end; { TEditor.Scroll_Down } + + +procedure TEditor.Scroll_Up; +{ This procedure will scroll the screen down, and always keep } +{ the cursor on the CurPos.Y position, but not necessarily on } +{ the CurPos.X. If CurPos.Y scrolls off the screen, the cursor } +{ will stay in the bottom left corner of the screen. This will } +{ simulate the same process in the IDE. The CurPos.X coordinate } +{ only messes up if we are on long lines and we then encounter } +{ a shorter or blank line beneath the current one as we scroll. } +{ In that case, it goes to the end of the new line. } +VAR + C : Sw_Word; { Position of CurPtr when we enter procedure. } + P : Sw_Word; { Position of CurPtr at any given time. } + W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). } +begin + { Remember current cursor position. Remember current CurPos.Y position. } + { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will } + { go to the top of the current screen. Reset the cursor to this new } + { position and then send FALSE to TrackCursor so we fool it into } + { decrementing Delta.Y by only -1. If we didn't do this it would try } + { to center the cursor on the screen by fiddling with Delta.Y. } + C := CurPtr; + W.Y := CurPos.Y; + P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1)); + SetCurPtr (P, 0); + TrackCursor (False); + { Now remember where the new CurPos.Y is. See if distance between new } + { CurPos.Y and old CurPos.Y are greater than the current screen size. } + { If they are, we need to move the cursor position itself up by one. } + { Otherwise, send the cursor back to our original CurPtr. } + W.X := CurPos.Y; + if W.Y - W.X > Size.Y - 1 then + SetCurPtr (LineMove (C, -1), 0) + else + SetCurPtr (C, 0); +end; { TEditor.Scroll_Up } + + +procedure TEditor.ScrollTo (X, Y : Sw_Integer); +begin + X := Max (0, Min (X, Limit.X - Size.X)); + Y := Max (0, Min (Y, Limit.Y - Size.Y)); + if (X <> Delta.X) or (Y <> Delta.Y) then + begin + Delta.X := X; + Delta.Y := Y; + Update (ufView); + end; +end; { TEditor.ScrollTo } + + +function TEditor.Search (const FindStr : String; Opts : Word) : Boolean; +VAR + I,Pos : Sw_Word; +begin + Search := False; + Pos := CurPtr; + repeat + if Opts and efCaseSensitive <> 0 then + I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr) + else + I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr); + if (I <> sfSearchFailed) then + begin + Inc (I, Pos); + if (Opts and efWholeWordsOnly = 0) or + not (((I <> 0) and (BufChar (I - 1) in WordChars)) or + ((I + Length (FindStr) <> BufLen) and + (BufChar (I + Length (FindStr)) in WordChars))) then + begin + Lock; + SetSelect (I, I + Length (FindStr), False); + TrackCursor (not CursorVisible); + Unlock; + Search := True; + Exit; + end + else + Pos := I + 1; + end; + until I = sfSearchFailed; +end; { TEditor.Search } + + +procedure TEditor.Select_Word; +{ This procedure will select the a word to put into the clipboard. } +{ I've added it just to maintain compatibility with the IDE editor. } +{ Note that selection starts at the current cursor position and ends } +{ when a space or the end of line is encountered. } +VAR + E : Sw_Word; { End of the current line. } + Select_Mode : Byte; { Allows us to turn select mode on inside procedure. } +begin + E := LineEnd (CurPtr); + { If the cursor is on a space or at the end of a line, abort. } + { Stupid action on users part for you can't select blanks! } + if (BufChar (CurPtr) = #32) or (CurPtr = E) then + Exit; + { Turn on select mode and tell editor to start selecting text. } + { As long as we have a character > a space (this is done to } + { exclude CR/LF pairs at end of a line) and we are NOT at the } + { end of a line, set the CurPtr to the next character. } + { Once we find a space or CR/LF, selection is done and we } + { automatically put the selected word into the Clipboard. } + Select_Mode := smExtend; + StartSelect; + while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do + SetCurPtr (NextChar (CurPtr), Select_Mode); + SetCurPtr (NextChar (CurPtr), Select_Mode); + ClipCopy; +end; {TEditor.Select_Word } + + +procedure TEditor.SetBufLen (Length : Sw_Word); +begin + BufLen := Length; + GapLen := BufSize - Length; + SelStart := 0; + SelEnd := 0; + CurPtr := 0; + CurPos.X:=0; + CurPos.Y:=0; + Delta.X:=0; + Delta.Y:=0; + GetLimits(Buffer^[GapLen], BufLen,Limit); + inc(Limit.X); + inc(Limit.Y); + DrawLine := 0; + DrawPtr := 0; + DelCount := 0; + InsCount := 0; + Modified := False; + Update (ufView); +end; { TEditor.SetBufLen } + + +function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean; +begin + SetBufSize := NewSize <= BufSize; +end; { TEditor.SetBufSize } + + +procedure TEditor.SetCmdState (Command : Word; Enable : Boolean); +VAR + S : TCommandSet; +begin + S := [Command]; + if Enable and (State and sfActive <> 0) then + EnableCommands (S) + else + DisableCommands (S); +end; { TEditor.SetCmdState } + + +procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte); +VAR + Anchor : Sw_Word; +begin + if SelectMode and smExtend = 0 then + Anchor := P + else + if CurPtr = SelStart then + Anchor := SelEnd + else + Anchor := SelStart; + if P < Anchor then + begin + if SelectMode and smDouble <> 0 then + begin + P := PrevLine (NextLine (P)); + Anchor := NextLine (PrevLine (Anchor)); + end; + SetSelect (P, Anchor, True); + end + else + begin + if SelectMode and smDouble <> 0 then + begin + P := NextLine (P); + Anchor := PrevLine (NextLine (Anchor)); + end; + SetSelect (Anchor, P, False); + end; +end; { TEditor.SetCurPtr } + + +procedure TEditor.Set_Place_Marker (Element : Byte); +{ This procedure sets a place marker for the CurPtr if ^K# is pressed. } +begin + if not IsClipboard then + Place_Marker[Element] := CurPtr; +end; { TEditor.Set_Place_Marker } + + +procedure TEditor.Set_Right_Margin; +{ This procedure will bring up a dialog box } +{ that allows the user to set Right_Margin. } +{ Values must be < MaxLineLength and > 9. } +VAR + Code : Integer; { Used for Val conversion. } + Margin_Data : TRightMarginRec; { Holds dialog results. } + Temp_Value : Sw_Integer; { Holds converted dialog value. } +begin + with Margin_Data do + begin + Str (Right_Margin, Margin_Position); + if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then + begin + val (Margin_Position, Temp_Value, Code); + if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then + Right_Margin := Temp_Value; + end; + end; +end; { TEditor.Set_Right_Margin } + + +procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean); +VAR + UFlags : Byte; + P : Sw_Word; + L : Sw_Word; +begin + if CurStart then + P := NewStart + else + P := NewEnd; + UFlags := ufUpdate; + if (NewStart <> SelStart) or (NewEnd <> SelEnd) then + if (NewStart <> NewEnd) or (SelStart <> SelEnd) then + UFlags := ufView; + if P <> CurPtr then + begin + if P > CurPtr then + begin + L := P - CurPtr; + Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L); + Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L)); + CurPtr := P; + end + else + begin + L := CurPtr - P; + CurPtr := P; + Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L)); + Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L); + end; + DrawLine := CurPos.Y; + DrawPtr := LineStart (P); + CurPos.X := CharPos (DrawPtr, P); + DelCount := 0; + InsCount := 0; + SetBufSize (BufLen); + end; + SelStart := NewStart; + SelEnd := NewEnd; + Update (UFlags); +end; { TEditor.Select } + + +procedure TEditor.SetState (AState : Word; Enable : Boolean); +begin + Inherited SetState (AState, Enable); + case AState of + sfActive: begin + if assigned(HScrollBar) then + HScrollBar^.SetState (sfVisible, Enable); + if assigned(VScrollBar) then + VScrollBar^.SetState (sfVisible, Enable); + if assigned(Indicator) then + Indicator^.SetState (sfVisible, Enable); + UpdateCommands; + end; + sfExposed: if Enable then Unlock; + end; +end; { TEditor.SetState } + + +procedure TEditor.Set_Tabs; +{ This procedure will bring up a dialog box } +{ that allows the user to set tab stops. } +VAR + Index : Sw_Integer; { Index into string array. } + Tab_Data : TTabStopRec; { Holds dialog results. } +begin + with Tab_Data do + begin + { Assign current Tab_Settings to Tab_String. } + { Bring up the tab dialog so user can set tabs. } + Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length); + if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then + begin + { If Tab_String comes back as empty then set Tab_Settings to nil. } + { Otherwise, find the last character in Tab_String that is not } + { a space and copy Tab_String into Tab_Settings up to that spot. } + if Length (Tab_String) = 0 then + begin + FillChar (Tab_Settings, SizeOf (Tab_Settings), #0); + Tab_Settings[0] := #0; + Exit; + end + else + begin + Index := Length (Tab_String); + while Tab_String[Index] <= #32 do + Dec (Index); + Tab_Settings := Copy (Tab_String, 1, Index); + end; + end; + end; +end; { TEditor.Set_Tabs } + + +procedure TEditor.StartSelect; +begin + HideSelect; + Selecting := True; +end; { TEditor.StartSelect } + + +procedure TEditor.Store (var S : Objects.TStream); +begin + Inherited Store (S); + PutPeerViewPtr (S, HScrollBar); + PutPeerViewPtr (S, VScrollBar); + PutPeerViewPtr (S, Indicator); + S.Write (BufSize, SizeOf (Sw_Word)); + S.Write (Canundo, SizeOf (Boolean)); + S.Write (AutoIndent, SizeOf (AutoIndent)); + S.Write (Line_Number, SizeOf (Line_Number)); + S.Write (Place_Marker, SizeOf (Place_Marker)); + S.Write (Right_Margin, SizeOf (Right_Margin)); + S.Write (Tab_Settings, SizeOf (Tab_Settings)); + S.Write (Word_Wrap, SizeOf (Word_Wrap)); +end; { Editor.Store } + + +procedure TEditor.Tab_Key (Select_Mode : Byte); +{ This function determines if we are in overstrike or insert mode, } +{ and then moves the cursor if overstrike, or adds spaces if insert. } +VAR + E : Sw_Word; { End of current line. } + Index : Sw_Integer; { Loop counter. } + Position : Sw_Integer; { CurPos.X position. } + S : Sw_Word; { Start of current line. } + Spaces : array [1..80] of Char; { Array to hold spaces for insertion. } +begin + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { Find the current horizontal cursor position. } + { Now loop through the Tab_Settings string and } + { find the next available tab stop. } + Position := CurPos.X + 1; + repeat + Inc (Position); + until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0])); + E := CurPos.X; + Index := 1; + { Now we enter a loop to go to the next tab position. } + { If we are in overwrite mode, we just move the cursor } + { through the text to the next tab stop. If we are in } + { insert mode, we add spaces to the Spaces array for } + { the number of times we loop. } + while Index < Position - E do + begin + if Overwrite then + begin + if (Position > LineEnd (CurPtr) - LineStart (CurPtr)) + or (Position > Ord (Tab_Settings[0])) then + begin + SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode); + Exit; + end + else + if CurPtr < BufLen then + SetCurPtr (NextChar (CurPtr), Select_Mode); + end + else + begin + if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then + begin + SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode); + Exit; + end + else + Spaces[Index] := #32; + end; + Inc (Index); + end; + { If we are insert mode, we insert spaces to the next tab stop. } + { When we're all done, the cursor will be sitting on the new tab stop. } + if not OverWrite then + InsertText (@Spaces, Index - 1, False); +end; { TEditor.Tab_Key } + + +procedure TEditor.ToggleInsMode; +begin + Overwrite := not Overwrite; + SetState (sfCursorIns, not GetState (sfCursorIns)); +end; { TEditor.ToggleInsMode } + + +procedure TEditor.TrackCursor (Center : Boolean); +begin + if Center then + ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2) + else + ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)), + Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y))); +end; { TEditor.TrackCursor } + + +procedure TEditor.Undo; +VAR + Length : Sw_Word; +begin + if (DelCount <> 0) or (InsCount <> 0) then + begin + Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount); + SelStart := CurPtr - InsCount; + SelEnd := CurPtr; + Length := DelCount; + DelCount := 0; + InsCount := 0; + InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True); + end; +end; { TEditor.Undo } + + +procedure TEditor.Unlock; +begin + if LockCount > 0 then + begin + Dec (LockCount); + if LockCount = 0 then + DoUpdate; + end; +end; { TEditor.Unlock } + + +procedure TEditor.Update (AFlags : Byte); +begin + UpdateFlags := UpdateFlags or AFlags; + if LockCount = 0 then + DoUpdate; +end; { TEditor.Update } + + +procedure TEditor.UpdateCommands; +begin + SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0)); + if not IsClipboard then + begin + SetCmdState (cmCut, HasSelection); + SetCmdState (cmCopy, HasSelection); + SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection)); + end; + SetCmdState (cmClear, HasSelection); + SetCmdState (cmFind, True); + SetCmdState (cmReplace, True); + SetCmdState (cmSearchAgain, True); +end; { TEditor.UpdateCommands } + + +procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word; + StartPtr,EndPtr : Sw_Word); +{ This procedure updates the position of the place markers } +{ as the user inserts and deletes text in the document. } +VAR + Element : Byte; { Place_Marker array element to traverse array with. } +begin + for Element := 1 to 10 do + begin + if AddCount > 0 then + begin + if (Place_Marker[Element] >= Curptr) + and (Place_Marker[Element] <> 0) then + Place_Marker[Element] := Place_Marker[Element] + AddCount; + end + else + begin + if Place_Marker[Element] >= StartPtr then + begin + if (Place_Marker[Element] >= StartPtr) and + (Place_Marker[Element] < EndPtr) then + Place_marker[Element] := 0 + else + begin + if integer (Place_Marker[Element]) - integer (KillCount) > 0 then + Place_Marker[Element] := Place_Marker[Element] - KillCount + else + Place_Marker[Element] := 0; + end; + end; + end; + end; + if AddCount > 0 then + BlankLine := BlankLine + AddCount + else + begin + if integer (BlankLine) - Integer (KillCount) > 0 then + BlankLine := BlankLine - KillCount + else + BlankLine := 0; + end; +end; { TEditor.Update_Place_Markers } + + +function TEditor.Valid (Command : Word) : Boolean; +begin + Valid := IsValid; +end; { TEditor.Valid } + + +{**************************************************************************** + TMEMO +****************************************************************************} + +constructor TMemo.Load (var S : Objects.TStream); +VAR + Length : Sw_Word; +begin + Inherited Load (S); + S.Read (Length, SizeOf (Sw_Word)); + if IsValid then + begin + S.Read (Buffer^[BufSize - Length], Length); + SetBufLen (Length); + end + else + S.Seek (S.GetPos + Length); +end; { TMemo.Load } + + +function TMemo.DataSize : Sw_Word; +begin + DataSize := BufSize + SizeOf (Sw_Word); +end; { TMemo.DataSize } + + +procedure TMemo.GetData (var Rec); +VAR + Data : TMemoData absolute Rec; +begin + Data.Length := BufLen; + Move (Buffer^, Data.Buffer, CurPtr); + Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr); + FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0); +end; { TMemo.GetData } + + +function TMemo.GetPalette : PPalette; +CONST + P : String[Length (CMemo)] = CMemo; +begin + GetPalette := @P; +end; { TMemo.GetPalette } + + +procedure TMemo.HandleEvent (var Event : Drivers.TEvent); +begin + if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then + Inherited HandleEvent (Event); +end; { TMemo.HandleEvent } + + +procedure TMemo.SetData (var Rec); +VAR + Data : TMemoData absolute Rec; +begin + Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length); + SetBufLen (Data.Length); +end; { TMemo.SetData } + + +procedure TMemo.Store (var S : Objects.TStream); +begin + Inherited Store (S); + S.Write (BufLen, SizeOf (Sw_Word)); + S.Write (Buffer^, CurPtr); + S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr); +end; { TMemo.Store } + + +{**************************************************************************** + TFILEEDITOR +****************************************************************************} + + +constructor TFileEditor.Init (var Bounds : TRect; + AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; + AFileName : FNameStr); +begin + Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0); + if AFileName <> '' then + begin + FileName := FExpand (AFileName); + if IsValid then + IsValid := LoadFile; + end; +end; { TFileEditor.Init } + + +constructor TFileEditor.Load (var S : Objects.TStream); +VAR + SStart,SEnd,Curs : Sw_Word; +begin + Inherited Load (S); + BufSize := 0; + S.Read (FileName[0], SizeOf (Char)); + S.Read (Filename[1], Length (FileName)); + if IsValid then + IsValid := LoadFile; + S.Read (SStart, SizeOf (Sw_Word)); + S.Read (SEnd, SizeOf (Sw_Word)); + S.Read (Curs, SizeOf (Sw_Word)); + if IsValid and (SEnd <= BufLen) then + begin + SetSelect (SStart, SEnd, Curs = SStart); + TrackCursor (True); + end; +end; { TFileEditor.Load } + + +procedure TFileEditor.DoneBuffer; +begin + if assigned(Buffer) then + DisposeBuffer (Buffer); +end; { TFileEditor.DoneBuffer } + + +procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent); +begin + Inherited HandleEvent (Event); + case Event.What of + Drivers.evCommand: + case Event.Command of + cmSave : Save; + cmSaveAs : SaveAs; + cmSaveDone : if Save then + Message (Owner, Drivers.evCommand, cmClose, nil); + else + Exit; + end; + else + Exit; + end; + ClearEvent (Event); +end; { TFileEditor.HandleEvent } + + +procedure TFileEditor.InitBuffer; +begin + NewBuffer(Pointer(Buffer), MinBufLength); +end; { TFileEditor.InitBuffer } + + +function TFileEditor.LoadFile: Boolean; +VAR + Length : Sw_Word; + FSize : Longint; + FRead : Sw_Integer; + F : File; +begin + LoadFile := False; + Length := 0; + Assign(F, FileName); + Reset(F, 1); + if IOResult <> 0 then + EditorDialog(edReadError, @FileName) + else + begin + FSize := FileSize(F); + if (FSize > MaxBufLength) or not SetBufSize(FSize) then + EditorDialog(edOutOfMemory, nil) + else + begin + BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead); + if (IOResult <> 0) or (FRead<>FSize) then + EditorDialog(edReadError, @FileName) + else + begin + LoadFile := True; + Length := FRead; + end; + end; + Close(F); + end; + SetBufLen(Length); +end; { TFileEditor.LoadFile } + + +function TFileEditor.Save : Boolean; +begin + if FileName = '' then + Save := SaveAs + else + Save := SaveFile; +end; { TFileEditor.Save } + + +function TFileEditor.SaveAs : Boolean; +begin + SaveAs := False; + if EditorDialog (edSaveAs, @FileName) <> cmCancel then + begin + FileName := FExpand (FileName); + Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil); + SaveAs := SaveFile; + if IsClipboard then + FileName := ''; + end; +end; { TFileEditor.SaveAs } + + +function TFileEditor.SaveFile : Boolean; +VAR + F : File; + BackupName : Objects.FNameStr; + D : DOS.DirStr; + N : DOS.NameStr; + E : DOS.ExtStr; +begin + SaveFile := False; + if Flags and efBackupFiles <> 0 then + begin + FSplit (FileName, D, N, E); + BackupName := D + N + '.bak'; + Assign (F, BackupName); + Erase (F); + Assign (F, FileName); + Rename (F, BackupName); + InOutRes := 0; + end; + Assign (F, FileName); + Rewrite (F, 1); + if IOResult <> 0 then + EditorDialog (edCreateError, @FileName) + else + begin + BlockWrite (F, Buffer^, CurPtr); + BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr); + if IOResult <> 0 then + EditorDialog (edWriteError, @FileName) + else + begin + Modified := False; + Update (ufUpdate); + SaveFile := True; + end; + Close (F); + end; +end; { TFileEditor.SaveFile } + + +function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean; +VAR + N : Sw_Word; +begin + SetBufSize := False; + if NewSize = 0 then + NewSize := MinBufLength + else + if NewSize > (MaxBufLength-MinBufLength) then + NewSize := MaxBufLength + else + NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1))); + if NewSize <> BufSize then + begin + if NewSize > BufSize then + if not SetBufferSize(pointer(Buffer), NewSize) then + Exit; + N := BufLen - CurPtr + DelCount; + Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N); + if NewSize < BufSize then + SetBufferSize(pointer(Buffer), NewSize); + BufSize := NewSize; + GapLen := BufSize - BufLen; + end; + SetBufSize := True; +end; { TFileEditor.SetBufSize } + + +procedure TFileEditor.Store (var S : Objects.TStream); +begin + Inherited Store (S); + S.Write (FileName, Length (FileName) + 1); + S.Write (SelStart, SizeOf (Sw_Word) * 3); +end; { TFileEditor.Store } + + +procedure TFileEditor.UpdateCommands; +begin + Inherited UpdateCommands; + SetCmdState (cmSave, True); + SetCmdState (cmSaveAs, True); + SetCmdState (cmSaveDone, True); +end; { TFileEditor.UpdateCommands } + + +function TFileEditor.Valid (Command : Word) : Boolean; +VAR + D : Integer; +begin + if Command = cmValid then + Valid := IsValid + else + begin + Valid := True; + if Modified then + begin + if FileName = '' then + D := edSaveUntitled + else + D := edSaveModify; + case EditorDialog (D, @FileName) of + cmYes : Valid := Save; + cmNo : Modified := False; + cmCancel : Valid := False; + end; + end; + end; +end; { TFileEditor.Valid } + + +{**************************************************************************** + TEDITWINDOW +****************************************************************************} + +constructor TEditWindow.Init (var Bounds : TRect; + FileName : Objects.FNameStr; + ANumber : Integer); +var + HScrollBar : PScrollBar; + VScrollBar : PScrollBar; + Indicator : PIndicator; + R : TRect; +begin + Inherited Init (Bounds, '', ANumber); + Options := Options or ofTileable; + + R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y); + HScrollBar := New (PScrollBar, Init (R)); + HScrollBar^.Hide; + Insert (HScrollBar); + + R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1); + VScrollBar := New (PScrollBar, Init (R)); + VScrollBar^.Hide; + Insert (VScrollBar); + + R.Assign (2, Size.Y - 1, 16, Size.Y); + Indicator := New (PIndicator, Init (R)); + Indicator^.Hide; + Insert (Indicator); + + GetExtent (R); + R.Grow (-1, -1); + Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName)); + Insert (Editor); +end; { TEditWindow.Init } + + +constructor TEditWindow.Load (var S : Objects.TStream); +begin + Inherited Load (S); + GetSubViewPtr (S, Editor); +end; { TEditWindow.Load } + + +procedure TEditWindow.Close; +begin + if Editor^.IsClipboard then + Hide + else + Inherited Close; +end; { TEditWindow.Close } + + +function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr; +begin + if Editor^.IsClipboard then + GetTitle := strings^.get(sClipboard) + else + if Editor^.FileName = '' then + GetTitle := strings^.get(sUntitled) + else + GetTitle := Editor^.FileName; +end; { TEditWindow.GetTile } + + +procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent); +begin + Inherited HandleEvent (Event); + if (Event.What = Drivers.evBroadcast) then + { and (Event.Command = cmUpdateTitle) then } + { Changed if statement above so I could test for cmBlugeonStats. } + { Stats would not show up when loading a file until a key was pressed. } + case Event.Command of + cmUpdateTitle : + begin + Frame^.DrawView; + ClearEvent (Event); + end; + cmBludgeonStats : + begin + Editor^.Update (ufStats); + ClearEvent (Event); + end; + end; +end; { TEditWindow.HandleEvent } + + +procedure TEditWindow.SizeLimits(var Min, Max: TPoint); +begin + inherited SizeLimits(Min, Max); + Min.X := 23; +end; + + +procedure TEditWindow.Store (var S : Objects.TStream); +begin + Inherited Store (S); + PutSubViewPtr (S, Editor); +end; { TEditWindow.Store } + + +procedure RegisterEditors; +begin + RegisterType (REditor); + RegisterType (RMemo); + RegisterType (RFileEditor); + RegisterType (RIndicator); + RegisterType (REditWindow); +end; { RegisterEditors } + + +end. { Unit NewEdit } diff --git a/fv/str.inc b/fv/str.inc new file mode 100644 index 0000000000..6bf78f42eb --- /dev/null +++ b/fv/str.inc @@ -0,0 +1,189 @@ +{ Strings } +sButtonDefault = 1; { Button default } +sButtonDisabled = 2; { Button disabled } +sButtonNormal = 3; { Button normal } +sButtonSelected = 4; { Button selected } +sButtonShadow = 5; { Button shadow } +sButtonShortcut = 6; { Button shortcut } +sChangeDirectory = 7; { Change Directory } +sClipboard = 8; { Clipboard } +sClusterNormal = 9; { Cluster normal } +sClusterSelected = 10; { Cluster selected } +sClusterShortcut = 11; { Cluster shortcut } +sColor = 12; { Color } +sColors = 13; { Colors } +sConfirm = 14; { Confirm } +sDeleteFile = 15; { Delete file?#13#10#13#3%s } +sDirectory = 16; { Directory } +sDisabled = 17; { Disabled } +sDrives = 18; { Drives } +sError = 19; { Error } +sFileAlreadyOpen = 20; { #3%s#13#10#13#3is already open in window %d. } +sFileCreateError = 21; { Error creating file %s } +sFileReadError = 22; { Error reading file %s } +sFileUntitled = 23; { Save untitled file? } +sFileWriteError = 24; { Error writing to file %s } +sFind = 25; { Find } +sFrameActive = 26; { Frame active } +sFrameBackground = 27; { Frame/background } +sFrameIcons = 28; { Frame icons } +sFramePassive = 29; { Frame passive } +sHighlight = 30; { Highlight } +sHistoryBarIcons = 31; { History bar icons } +sHistoryBarPage = 32; { History bar page } +sHistoryButton = 33; { History button } +sHistorySides = 34; { History sides } +sInformation = 35; { Information } +sInformationPane = 36; { Information pane } +sInputArrow = 37; { Input arrow } +sInputNormal = 38; { Input normal } +sInputSelected = 39; { Input selected } +sInvalidCharacter = 40; { Invalid character in input } +sInvalidDirectory = 41; { Invalid directory. } +sInvalidDriveOrDir = 42; { Invalid drive or directory. } +sInvalidFileName = 43; { Invalid file name. } +sInvalidPicture = 44; { Input does not conform to picture: %s } +sInvalidValue = 45; { Value not in the range %d to %d } +sInverse = 46; { Inverse } +sJumpTo = 47; { Jump To } +sLabelNormal = 48; { Label normal } +sLabelSelected = 49; { Label selected } +sLabelShortcut = 50; { Label shortcut } +sListDivider = 51; { List divider } +sListFocused = 52; { List focused } +sListNormal = 53; { List normal } +sListSelected = 54; { List selected } +sModified = 55; { #3%s#13#10#13#3has been modified. Save? } +sNoName = 56; { NONAME } +sNormal = 57; { Normal } +sNormalText = 58; { Normal text } +sNotInList = 59; { Input not in valid-list } +sOpen = 60; { Open } +sOutOfMemory = 61; { Not enough memory for this operation. } +sOutOfUnNamedWindows = 62; { Out of unnamed window numbers. Save or discard some unnamed files and try again. } +sPasteNotPossible = 63; { Wordwrap on: Paste not possible in current margins when at end of line. } +sReformatDocument = 64; { Reformat Document } +sReformatNotPossible = 65; { Paragraph reformat not possible while trying to wrap current line with current margins. } +sReformattingTheDocument = 66; { Reformatting the document: } +sReplace = 67; { Replace } +sReplaceFile = 68; { Replace file?#13#10#13#3%s } +sReplaceNotPossible = 69; { Wordwrap on: Replace not possible in current margins when at end of line. } +sReplaceThisOccurence = 70; { Replace this occurence? } +sRightMargin = 71; { Right Margin } +sSaveAs = 72; { Save As } +sScrollbarIcons = 73; { Scroll bar icons } +sScrollbarPage = 74; { Scroll bar page } +sSearchStringNotFound = 75; { Search string not found. } +sSelectFormatStart = 76; { Select Format Start } +sSelectWhereToBegin = 77; { Please select where to begin. } +sSelected = 78; { Selected } +sSelectedDisabled = 79; { Selected disabled } +sSetting = 80; { Setting: } +sShortcut = 81; { Shortcut } +sShortcutSelected = 82; { ShortcutSelected } +sStaticText = 83; { Static text } +sTabSettings = 84; { Tab Settings } +sText = 85; { Text } +sTooManyFiles = 86; { Too many files. } +sTypeExitOnReturn = 87; { Type EXIT to return... } +sUnderline = 88; { Underline } +sUnknownDialog = 89; { Unknown dialog requested! } +sUntitled = 90; { Untitled } +sWarning = 91; { Warning } +sWindowList = 92; { Window List } +sWordWrapNotPossible = 93; { Wordwrap on: Wordwrap not possible in current margins with continuous line. } +sWordWrapOff = 94; { You must turn on wordwrap before you can reformat. } +smApr = 95; { Apr } +smAug = 96; { Aug } +smDec = 97; { Dec } +smFeb = 98; { Feb } +smJan = 99; { Jan } +smJul = 100; { Jul } +smJun = 101; { Jun } +smMar = 102; { Mar } +smMay = 103; { May } +smNov = 104; { Nov } +smOct = 105; { Oct } +smSep = 106; { Sep } +{ Labels } +slAbout = 107; { ~A~bout } +slAltF1 = 108; { Alt+F1 } +slAltF3Close = 109; { ~Alt+F3~ Close } +slAltXExit = 110; { ~Alt-X~ Exit } +slBackground = 111; { ~B~ackground } +slCancel = 112; { Cancel } +slCascade = 113; { C~a~scade } +slCaseSensitive = 114; { ~C~ase sensitive } +slChDir = 115; { ~C~hdir } +slChangeDir = 116; { ~C~hange dir... } +slClear = 117; { C~l~ear } +slClose = 118; { ~C~lose } +slCloseAll = 119; { Cl~o~se all } +slColor = 120; { ~C~olor } +slContents = 121; { ~C~ontents } +slCopy = 122; { ~C~opy } +slCtrlF1 = 123; { Ctrl+F1 } +slCurrentLine = 124; { ~C~urrent line } +slCut = 125; { Cu~t~ } +slDOSShell = 126; { ~D~OS shell } +slDelete = 127; { ~D~elete } +slDirectoryName = 128; { Directory ~n~ame } +slDirectoryTree = 129; { Directory ~t~ree } +slEdit = 130; { ~E~dit } +slEntireDocument = 131; { ~E~ntire document } +slExit = 132; { E~x~it } +slF10Menu = 133; { ~F10~ Menu } +slF1Help = 134; { ~F1~ Help } +slF3Open = 135; { ~F3~ Open } +slFile = 136; { ~F~ile } +slFiles = 137; { ~F~iles } +slForeground = 138; { ~F~oreground } +slGroup = 139; { ~G~roup } +slHelp = 140; { ~H~elp } +slIndex = 141; { ~I~ndex } +slItem = 142; { ~I~tem } +slLineNumber = 143; { ~L~ine number } +slName = 144; { ~N~ame } +slNew = 145; { ~N~ew } +slNewText = 146; { ~N~ew text } +slNext = 147; { ~N~ext } +slNo = 148; { ~N~o } +slOk = 149; { O~k~ } +slOpen = 150; { ~O~pen } +slOpenDots = 151; { ~O~pen... } +slPaste = 152; { ~P~aste } +slPrevious = 153; { ~P~revious } +slPreviousTopic = 154; { ~P~revious topic } +slPromptOnReplace = 155; { ~P~rompt on replace } +slReformatDocument = 156; { ~R~eformat document } +slReplace = 157; { ~R~eplace } +slReplaceAll = 158; { ~R~eplace all } +slRevert = 159; { ~R~evert } +slSave = 160; { ~S~ave } +slSaveAll = 161; { Save a~l~l } +slSaveAs = 162; { S~a~ve as... } +slSaveFileAs = 163; { ~S~ave file as } +slShiftF1 = 164; { Shift+F1 } +slSizeMove = 165; { ~S~ize/Move } +slTextToFind = 166; { ~T~ext to find } +slTile = 167; { ~T~ile } +slTopicSearch = 168; { ~T~opic search } +slUndo = 169; { ~U~ndo } +slUsingHelp = 170; { ~U~sing help } +slWholeWordsOnly = 171; { ~W~hole words only } +slWindow = 172; { ~W~indow } +slWindows = 173; { ~W~indows } +slYes = 174; { ~Y~es } +slZoom = 175; { ~Z~oom } +slAltF3 = 176; { Alt+F3 } +slAltX = 177; { Alt+X } +slF2 = 178; { F2 } +slF3 = 179; { F3 } +slF5 = 180; { F5 } +slF6 = 181; { F6 } +slCtrlDel = 182; { Ctrl+Del } +slCtrlF5 = 183; { Ctrl+F5 } +slCtrlIns = 184; { Ctrl+Ins } +slShiftDel = 185; { Shift+Del } +slShiftF6 = 186; { Shift+F6 } +slShiftIns = 187; { Shift+Ins } diff --git a/fv/strtxt.inc b/fv/strtxt.inc new file mode 100644 index 0000000000..fc854b7663 --- /dev/null +++ b/fv/strtxt.inc @@ -0,0 +1,194 @@ +procedure InitResStrings; +begin + Strings^.Put(sButtonDefault,'Button default'); + Strings^.Put(sButtonDisabled,'Button disabled'); + Strings^.Put(sButtonNormal,'Button normal'); + Strings^.Put(sButtonSelected,'Button selected'); + Strings^.Put(sButtonShadow,'Button shadow'); + Strings^.Put(sButtonShortcut,'Button shortcut'); + Strings^.Put(sChangeDirectory,'Change Directory'); + Strings^.Put(sClipboard,'Clipboard'); + Strings^.Put(sClusterNormal,'Cluster normal'); + Strings^.Put(sClusterSelected,'Cluster selected'); + Strings^.Put(sClusterShortcut,'Cluster shortcut'); + Strings^.Put(sColor,'Color'); + Strings^.Put(sColors,'Colors'); + Strings^.Put(sConfirm,'Confirm'); + Strings^.Put(sDeleteFile,'Delete file?'#13#10#13#3'%s'); + Strings^.Put(sDirectory,'Directory'); + Strings^.Put(sDisabled,'Disabled'); + Strings^.Put(sDrives,'Drives'); + Strings^.Put(sError,'Error'); + Strings^.Put(sFileAlreadyOpen,''#3'%s'#13#10#13#3'is already open in window %d.'); + Strings^.Put(sFileCreateError,'Error creating file %s'); + Strings^.Put(sFileReadError,'Error reading file %s'); + Strings^.Put(sFileUntitled,'Save untitled file?'); + Strings^.Put(sFileWriteError,'Error writing to file %s'); + Strings^.Put(sFind,'Find'); + Strings^.Put(sFrameActive,'Frame active'); + Strings^.Put(sFrameBackground,'Frame/background'); + Strings^.Put(sFrameIcons,'Frame icons'); + Strings^.Put(sFramePassive,'Frame passive'); + Strings^.Put(sHighlight,'Highlight'); + Strings^.Put(sHistoryBarIcons,'History bar icons'); + Strings^.Put(sHistoryBarPage,'History bar page'); + Strings^.Put(sHistoryButton,'History button'); + Strings^.Put(sHistorySides,'History sides'); + Strings^.Put(sInformation,'Information'); + Strings^.Put(sInformationPane,'Information pane'); + Strings^.Put(sInputArrow,'Input arrow'); + Strings^.Put(sInputNormal,'Input normal'); + Strings^.Put(sInputSelected,'Input selected'); + Strings^.Put(sInvalidCharacter,'Invalid character in input'); + Strings^.Put(sInvalidDirectory,'Invalid directory.'); + Strings^.Put(sInvalidDriveOrDir,'Invalid drive or directory.'); + Strings^.Put(sInvalidFileName,'Invalid file name.'); + Strings^.Put(sInvalidPicture,'Input does not conform to picture: %s'); + Strings^.Put(sInvalidValue,'Value not in the range %d to %d'); + Strings^.Put(sInverse,'Inverse'); + Strings^.Put(sJumpTo,'Jump To'); + Strings^.Put(sLabelNormal,'Label normal'); + Strings^.Put(sLabelSelected,'Label selected'); + Strings^.Put(sLabelShortcut,'Label shortcut'); + Strings^.Put(sListDivider,'List divider'); + Strings^.Put(sListFocused,'List focused'); + Strings^.Put(sListNormal,'List normal'); + Strings^.Put(sListSelected,'List selected'); + Strings^.Put(sModified,''#3'%s'#13#10#13#3'has been modified. Save?'); + Strings^.Put(sNoName,'NONAME'); + Strings^.Put(sNormal,'Normal'); + Strings^.Put(sNormalText,'Normal text'); + Strings^.Put(sNotInList,'Input not in valid-list'); + Strings^.Put(sOpen,'Open'); + Strings^.Put(sOutOfMemory,'Not enough memory for this operation.'); + Strings^.Put(sOutOfUnNamedWindows,'Out of unnamed window numbers. Save or discard some unnamed files and try again.'); + Strings^.Put(sPasteNotPossible,'Wordwrap on: Paste not possible in current margins when at end of line.'); + Strings^.Put(sReformatDocument,'Reformat Document'); + Strings^.Put(sReformatNotPossible,'Paragraph reformat not possible while trying to wrap current line with current margins.'); + Strings^.Put(sReformattingTheDocument,'Reformatting the document:'); + Strings^.Put(sReplace,'Replace'); + Strings^.Put(sReplaceFile,'Replace file?'#13#10#13#3'%s'); + Strings^.Put(sReplaceNotPossible,'Wordwrap on: Replace not possible in current margins when at end of line.'); + Strings^.Put(sReplaceThisOccurence,'Replace this occurence?'); + Strings^.Put(sRightMargin,'Right Margin'); + Strings^.Put(sSaveAs,'Save As'); + Strings^.Put(sScrollbarIcons,'Scroll bar icons'); + Strings^.Put(sScrollbarPage,'Scroll bar page'); + Strings^.Put(sSearchStringNotFound,'Search string not found.'); + Strings^.Put(sSelectFormatStart,'Select Format Start'); + Strings^.Put(sSelectWhereToBegin,'Please select where to begin.'); + Strings^.Put(sSelected,'Selected'); + Strings^.Put(sSelectedDisabled,'Selected disabled'); + Strings^.Put(sSetting,'Setting:'); + Strings^.Put(sShortcut,'Shortcut'); + Strings^.Put(sShortcutSelected,'ShortcutSelected'); + Strings^.Put(sStaticText,'Static text'); + Strings^.Put(sTabSettings,'Tab Settings'); + Strings^.Put(sText,'Text'); + Strings^.Put(sTooManyFiles,'Too many files.'); + Strings^.Put(sTypeExitOnReturn,'Type EXIT to return...'); + Strings^.Put(sUnderline,'Underline'); + Strings^.Put(sUnknownDialog,'Unknown dialog requested!'); + Strings^.Put(sUntitled,'Untitled'); + Strings^.Put(sWarning,'Warning'); + Strings^.Put(sWindowList,'Window List'); + Strings^.Put(sWordWrapNotPossible,'Wordwrap on: Wordwrap not possible in current margins with continuous line.'); + Strings^.Put(sWordWrapOff,'You must turn on wordwrap before you can reformat.'); + Strings^.Put(smApr,'Apr'); + Strings^.Put(smAug,'Aug'); + Strings^.Put(smDec,'Dec'); + Strings^.Put(smFeb,'Feb'); + Strings^.Put(smJan,'Jan'); + Strings^.Put(smJul,'Jul'); + Strings^.Put(smJun,'Jun'); + Strings^.Put(smMar,'Mar'); + Strings^.Put(smMay,'May'); + Strings^.Put(smNov,'Nov'); + Strings^.Put(smOct,'Oct'); + Strings^.Put(smSep,'Sep'); +end; + +procedure InitResLabels; +begin + Labels^.Put(slAbout,'~A~bout'); + Labels^.Put(slAltF1,'Alt+F1'); + Labels^.Put(slAltF3Close,'~Alt+F3~ Close'); + Labels^.Put(slAltXExit,'~Alt-X~ Exit'); + Labels^.Put(slBackground,'~B~ackground'); + Labels^.Put(slCancel,'Cancel'); + Labels^.Put(slCascade,'C~a~scade'); + Labels^.Put(slCaseSensitive,'~C~ase sensitive'); + Labels^.Put(slChDir,'~C~hdir'); + Labels^.Put(slChangeDir,'~C~hange dir...'); + Labels^.Put(slClear,'C~l~ear'); + Labels^.Put(slClose,'~C~lose'); + Labels^.Put(slCloseAll,'Cl~o~se all'); + Labels^.Put(slColor,'~C~olor'); + Labels^.Put(slContents,'~C~ontents'); + Labels^.Put(slCopy,'~C~opy'); + Labels^.Put(slCtrlF1,'Ctrl+F1'); + Labels^.Put(slCurrentLine,'~C~urrent line'); + Labels^.Put(slCut,'Cu~t~'); + Labels^.Put(slDOSShell,'~D~OS shell'); + Labels^.Put(slDelete,'~D~elete'); + Labels^.Put(slDirectoryName,'Directory ~n~ame'); + Labels^.Put(slDirectoryTree,'Directory ~t~ree'); + Labels^.Put(slEdit,'~E~dit'); + Labels^.Put(slEntireDocument,'~E~ntire document'); + Labels^.Put(slExit,'E~x~it'); + Labels^.Put(slF10Menu,'~F10~ Menu'); + Labels^.Put(slF1Help,'~F1~ Help'); + Labels^.Put(slF3Open,'~F3~ Open'); + Labels^.Put(slFile,'~F~ile'); + Labels^.Put(slFiles,'~F~iles'); + Labels^.Put(slForeground,'~F~oreground'); + Labels^.Put(slGroup,'~G~roup'); + Labels^.Put(slHelp,'~H~elp'); + Labels^.Put(slIndex,'~I~ndex'); + Labels^.Put(slItem,'~I~tem'); + Labels^.Put(slLineNumber,'~L~ine number'); + Labels^.Put(slName,'~N~ame'); + Labels^.Put(slNew,'~N~ew'); + Labels^.Put(slNewText,'~N~ew text'); + Labels^.Put(slNext,'~N~ext'); + Labels^.Put(slNo,'~N~o'); + Labels^.Put(slOk,'O~k~'); + Labels^.Put(slOpen,'~O~pen'); + Labels^.Put(slOpenDots,'~O~pen...'); + Labels^.Put(slPaste,'~P~aste'); + Labels^.Put(slPrevious,'~P~revious'); + Labels^.Put(slPreviousTopic,'~P~revious topic'); + Labels^.Put(slPromptOnReplace,'~P~rompt on replace'); + Labels^.Put(slReformatDocument,'~R~eformat document'); + Labels^.Put(slReplace,'~R~eplace'); + Labels^.Put(slReplaceAll,'~R~eplace all'); + Labels^.Put(slRevert,'~R~evert'); + Labels^.Put(slSave,'~S~ave'); + Labels^.Put(slSaveAll,'Save a~l~l'); + Labels^.Put(slSaveAs,'S~a~ve as...'); + Labels^.Put(slSaveFileAs,'~S~ave file as'); + Labels^.Put(slShiftF1,'Shift+F1'); + Labels^.Put(slSizeMove,'~S~ize/Move'); + Labels^.Put(slTextToFind,'~T~ext to find'); + Labels^.Put(slTile,'~T~ile'); + Labels^.Put(slTopicSearch,'~T~opic search'); + Labels^.Put(slUndo,'~U~ndo'); + Labels^.Put(slUsingHelp,'~U~sing help'); + Labels^.Put(slWholeWordsOnly,'~W~hole words only'); + Labels^.Put(slWindow,'~W~indow'); + Labels^.Put(slWindows,'~W~indows'); + Labels^.Put(slYes,'~Y~es'); + Labels^.Put(slZoom,'~Z~oom'); + Labels^.Put(slAltF3,'Alt+F3'); + Labels^.Put(slAltX,'Alt+X'); + Labels^.Put(slF2,'F2'); + Labels^.Put(slF3,'F3'); + Labels^.Put(slF5,'F5'); + Labels^.Put(slF6,'F6'); + Labels^.Put(slCtrlDel,'Ctrl+Del'); + Labels^.Put(slCtrlF5,'Ctrl+F5'); + Labels^.Put(slCtrlIns,'Ctrl+Ins'); + Labels^.Put(slShiftDel,'Shift+Del'); + Labels^.Put(slShiftF6,'Shift+F6'); + Labels^.Put(slShiftIns,'Shift+Ins'); +end; diff --git a/fvision/callspec.pas b/fvision/callspec.pas new file mode 100644 index 0000000000..b25caaeefa --- /dev/null +++ b/fvision/callspec.pas @@ -0,0 +1,432 @@ +{ + $Id$ + + This unit provides compiler-independent mechanisms to call special + functions, i.e. local functions/procedures, constructors, methods, + destructors, etc. As there are no procedural variables for these + special functions, there is no Pascal way to call them directly. + + Copyright (c) 1997 Matthias K"oppe + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + ****************************************************************************} +unit CallSpec; + +{ + As of this version, the following compilers are supported. Please + port CallSpec to other compilers (including earlier versions) and + send your code to the above address. + + Compiler Comments + --------------------------- ------------------------------------- + Turbo Pascal 6.0 + Borland/Turbo Pascal 7.0 + FPC Pascal 0.99.8 +} + +interface + +{$i platform.inc} + +{ + The frame pointer points to the local variables of a procedure. + Use CurrentFramePointer to address the locals of the current procedure; + use PreviousFramePointer to addess the locals of the calling procedure. +} +type +{$ifdef BIT_16} + FramePointer = Word; +{$endif} +{$ifdef BIT_32} + FramePointer = pointer; +{$endif} + +function CurrentFramePointer: FramePointer; +function PreviousFramePointer: FramePointer; + +{ This version of CallSpec supports four classes of special functions. + (Please write if you need other classes.) + For each, two types of argument lists are allowed: + + `Void' indicates special functions with no explicit arguments. + Sample: constructor T.Init; + `Pointer' indicates special functions with one explicit pointer argument. + Sample: constructor T.Load(var S: TStream); +} + +{ Constructor calls. + + Ctor Pointer to the constructor. + Obj Pointer to the instance. NIL if new instance to be allocated. + VMT Pointer to the VMT (obtained by TypeOf()). + returns Pointer to the instance. +} +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; + +{ Method calls. + + Method Pointer to the method. + Obj Pointer to the instance. NIL if new instance to be allocated. + returns Pointer to the instance. +} +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; + +{ Local-function/procedure calls. + + Func Pointer to the local function (which must be far-coded). + Frame Frame pointer of the wrapping function. +} + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; + +{ Calls of functions/procedures local to methods. + + Func Pointer to the local function (which must be far-coded). + Frame Frame pointer of the wrapping method. + Obj Pointer to the object that the method belongs to. +} +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; + + +implementation + +{$ifdef PPC_FPC} + +{$ifdef CPUI386} +{$ASMMODE ATT} +{$endif CPUI386} + +{ This indicates an FPC version which uses the same call scheme for + method-local and procedure-local procedures, but which expects the + ESI register be loaded with the Self pointer in method-local procs. } + +type + VoidLocal = function(_EBP: FramePointer): pointer; + PointerLocal = function(_EBP: FramePointer; Param1: pointer): pointer; + VoidMethodLocal = function(_EBP: FRAMEPOINTER): pointer; + PointerMethodLocal = function(_EBP: FRAMEPOINTER; Param1: pointer): pointer; + VoidConstructor = function(VMT: pointer; Obj: pointer): pointer; + PointerConstructor = function(VMT: pointer; Obj: pointer; Param1: pointer): pointer; + VoidMethod = function(Obj: pointer): pointer; + PointerMethod = function(Obj: pointer; Param1: pointer): pointer; + + +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + + CallVoidConstructor := VoidConstructor(Ctor)(VMT, Obj) +end; + + +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerConstructor := PointerConstructor(Ctor)(VMT, Obj, Param1) +end; + + +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallVoidMethod := VoidMethod(Method)(Obj) +end; + + +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerMethod := PointerMethod(Method)(Obj, Param1) +end; + + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; +begin + CallVoidLocal := VoidLocal(Func)(Frame) +end; + + +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; +begin + CallPointerLocal := PointerLocal(Func)(Frame, Param1) +end; + + +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallVoidMethodLocal := VoidMethodLocal(Func)(Frame) +end; + + +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; +begin + { load the object pointer } +{$ifdef CPUI386} + asm + movl Obj, %esi + end; +{$endif CPUI386} +{$ifdef CPU68K} + asm + move.l Obj, a5 + end; +{$endif CPU68K} + CallPointerMethodLocal := PointerMethodLocal(Func)(Frame, Param1) +end; + + +function CurrentFramePointer: FramePointer;assembler; +{$ifdef CPUI386} +asm + movl %ebp,%eax +end ['EAX']; +{$endif CPUI386} +{$ifdef CPU68K} +asm + move.l a6, d0 +end['D0']; +{$endif CPU68K} + + +function PreviousFramePointer: FramePointer;assembler; +{$ifdef CPUI386} +asm + movl (%ebp),%eax +end ['EAX']; +{$endif CPUI386} +{$ifdef CPU68K} +asm + move.l (a6), d0 +end['D0']; +{$endif CPU68K} + +{$endif PPC_FPC} + + +{$ifdef PPC_BP} +type + VoidConstructor = function(VmtOfs: Word; Obj: pointer): pointer; + PointerConstructor = function(Param1: pointer; VmtOfs: Word; Obj: pointer): pointer; + VoidMethod = function(Obj: pointer): pointer; + PointerMethod = function(Param1: pointer; Obj: pointer): pointer; + +function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer; +begin + CallVoidConstructor := VoidConstructor(Ctor)(Ofs(VMT^), Obj) +end; + + +function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer; +begin + CallPointerConstructor := PointerConstructor(Ctor)(Param1, Ofs(VMT^), Obj) +end; + + +function CallVoidMethod(Method: pointer; Obj: pointer): pointer; +begin + CallVoidMethod := VoidMethod(Method)(Obj) +end; + + +function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer; +begin + CallPointerMethod := PointerMethod(Method)(Param1, Obj) +end; + + +function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; assembler; +asm +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; assembler; +asm + mov ax, word ptr Param1 + mov dx, word ptr Param1+2 + push dx + push ax +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; assembler; +asm +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; assembler; +asm + mov ax, word ptr Param1 + mov dx, word ptr Param1+2 + push dx + push ax +{$IFDEF Windows} + MOV AX,[Frame] + AND AL,0FEH + PUSH AX +{$ELSE} + push [Frame] +{$ENDIF} + call dword ptr Func +end; + + +function CurrentFramePointer: FramePointer; assembler; +asm + mov ax, bp +end; + + +function PreviousFramePointer: FramePointer; assembler; +asm + mov ax, ss:[bp] +end; + +{$endif PPC_BP} + + +end. +{ + $Log$ + Revision 1.1 2001-08-05 02:10:26 peter + * more files + + Revision 1.3 2001/07/30 08:27:58 pierre + * fix I386 compilation problem + + Revision 1.2 2001/07/29 20:23:18 pierre + * support for m68k cpu + + Revision 1.1 2001/01/29 21:56:04 peter + * updates for new fpcmake + + Revision 1.1 2001/01/29 11:31:26 marco + * added from API. callspec renamed to .pp + + Revision 1.1 2000/07/13 06:29:38 michael + + Initial import + + Revision 1.1 2000/01/06 01:20:30 peter + * moved out of packages/ back to topdir + + Revision 1.1 1999/12/23 19:36:47 peter + * place unitfiles in target dirs + + Revision 1.1 1999/11/24 23:36:37 peter + * moved to packages dir + + Revision 1.2 1998/12/16 21:57:16 peter + * fixed currentframe,previousframe + + testcall to test the callspec unit + + Revision 1.1 1998/12/04 12:48:24 peter + * moved some dirs + + Revision 1.5 1998/12/04 09:53:44 peter + * removed objtemp global var + + Revision 1.4 1998/11/24 17:14:24 peter + * fixed esi loading + + + Date Version Who Comments + ---------- -------- ------- ------------------------------------- + 19-Sep-97 0.1 mkoeppe Initial version. + 22-Sep-97 0.11 fk 0.9.3 support added, self isn't expected + on the stack in local procedures of methods + 23-Sep-97 0.12 mkoeppe Cleaned up 0.9.3 conditionals. + 03-Oct-97 0.13 mkoeppe Fixed esi load in FPC 0.9 + 22-Oct-98 0.14 pfv 0.99.8 support for FPC +} diff --git a/fvision/editors.pas b/fvision/editors.pas new file mode 100644 index 0000000000..ad98c3e9f6 --- /dev/null +++ b/fvision/editors.pas @@ -0,0 +1,3733 @@ +unit Editors; + +{$i platform.inc} + +{$ifdef PPC_FPC} + {$H-} +{$else} + {$F+,O+,E+,N+} +{$endif} +{$X+,R-,I-,Q-,V-} +{$ifndef OS_LINUX} + {$S-} +{$endif} + + +{$define UNIXLF} + +interface + +uses + Objects, Drivers,Views,Dialogs,FVCommon,FVConsts; + +const + { Length constants. } + Tab_Stop_Length = 74; + +{$ifdef PPC_BP} + MaxLineLength = 1024; + MinBufLength = $1000; + MaxBufLength = $ff00; + NotFoundValue = $ffff; + LineInfoGrow = 256; + MaxLines = 16000; +{$else} + MaxLineLength = 4096; + MinBufLength = $1000; + MaxBufLength = $7fffff00; + NotFoundValue = $ffffffff; + LineInfoGrow = 1024; + MaxLines = $7ffffff; +{$endif} + + + { Editor constants for dialog boxes. } + edOutOfMemory = 0; + edReadError = 1; + edWriteError = 2; + edCreateError = 3; + edSaveModify = 4; + edSaveUntitled = 5; + edSaveAs = 6; + edFind = 7; + edSearchFailed = 8; + edReplace = 9; + edReplacePrompt = 10; + + edJumpToLine = 11; + edPasteNotPossible = 12; + edReformatDocument = 13; + edReformatNotAllowed = 14; + edReformNotPossible = 15; + edReplaceNotPossible = 16; + edRightMargin = 17; + edSetTabStops = 18; + edWrapNotPossible = 19; + + { Editor flag constants for dialog options. } + efCaseSensitive = $0001; + efWholeWordsOnly = $0002; + efPromptOnReplace = $0004; + efReplaceAll = $0008; + efDoReplace = $0010; + efBackupFiles = $0100; + + { Constants for object palettes. } + CIndicator = #2#3; + CEditor = #6#7; + CMemo = #26#27; + +type + TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word; + + PIndicator = ^TIndicator; + TIndicator = object (TView) + Location : Objects.TPoint; + Modified : Boolean; + AutoIndent : Boolean; { Added boolean for AutoIndent mode. } + WordWrap : Boolean; { Added boolean for WordWrap mode. } + constructor Init (var Bounds : TRect); + procedure Draw; virtual; + function GetPalette : PPalette; virtual; + procedure SetState (AState : Word; Enable : Boolean); virtual; + procedure SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean; + IsModified : Boolean; + IsWordWrap : Boolean); + end; + + TLineInfoRec = record + Len,Attr : Sw_word; + end; + TLineInfoArr = array[0..MaxLines] of TLineInfoRec; + PLineInfoArr = ^TLineInfoArr; + + PLineInfo = ^TLineInfo; + TLineInfo = object + Info : PLineInfoArr; + MaxPos : Sw_Word; + constructor Init; + destructor Done; + procedure Grow(pos:Sw_word); + procedure SetLen(pos,val:Sw_Word); + procedure SetAttr(pos,val:Sw_Word); + function GetLen(pos:Sw_Word):Sw_Word; + function GetAttr(pos:Sw_Word):Sw_Word; + end; + + + PEditBuffer = ^TEditBuffer; + TEditBuffer = array[0..MaxBufLength] of Char; + + PEditor = ^TEditor; + TEditor = object (TView) + HScrollBar : PScrollBar; + VScrollBar : PScrollBar; + Indicator : PIndicator; + Buffer : PEditBuffer; + BufSize : Sw_Word; + BufLen : Sw_Word; + GapLen : Sw_Word; + SelStart : Sw_Word; + SelEnd : Sw_Word; + CurPtr : Sw_Word; + CurPos : Objects.TPoint; + Delta : Objects.TPoint; + Limit : Objects.TPoint; + DrawLine : Sw_Integer; + DrawPtr : Sw_Word; + DelCount : Sw_Word; + InsCount : Sw_Word; + Flags : Longint; + IsReadOnly : Boolean; + IsValid : Boolean; + CanUndo : Boolean; + Modified : Boolean; + Selecting : Boolean; + Overwrite : Boolean; + AutoIndent : Boolean; + NoSelect : Boolean; + TabSize : Sw_Word; { tabsize for displaying } + BlankLine : Sw_Word; { First blank line after a paragraph. } + Word_Wrap : Boolean; { Added boolean to toggle wordwrap on/off. } + Line_Number : string[8]; { Holds line number to jump to. } + Right_Margin : Sw_Integer; { Added integer to set right margin. } + Tab_Settings : String[Tab_Stop_Length]; { Added string to hold tab stops. } + + constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; ABufSize : Sw_Word); + constructor Load (var S : Objects.TStream); + destructor Done; virtual; + function BufChar (P : Sw_Word) : Char; + function BufPtr (P : Sw_Word) : Sw_Word; + procedure ChangeBounds (var Bounds : TRect); virtual; + procedure ConvertEvent (var Event : Drivers.TEvent); virtual; + function CursorVisible : Boolean; + procedure DeleteSelect; + procedure DoneBuffer; virtual; + procedure Draw; virtual; + procedure FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual; + function GetPalette : PPalette; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure InitBuffer; virtual; + function InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean; + function InsertFrom (Editor : PEditor) : Boolean; virtual; + function InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean; + procedure ScrollTo (X, Y : Sw_Integer); + function Search (const FindStr : String; Opts : Word) : Boolean; + function SetBufSize (NewSize : Sw_Word) : Boolean; virtual; + procedure SetCmdState (Command : Word; Enable : Boolean); + procedure SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean); + procedure SetCurPtr (P : Sw_Word; SelectMode : Byte); + procedure SetState (AState : Word; Enable : Boolean); virtual; + procedure Store (var S : Objects.TStream); + procedure TrackCursor (Center : Boolean); + procedure Undo; + procedure UpdateCommands; virtual; + function Valid (Command : Word) : Boolean; virtual; + + private + KeyState : Integer; + LockCount : Byte; + UpdateFlags : Byte; + Place_Marker : Array [1..10] of Sw_Word; { Inserted array to hold place markers. } + Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. } + + procedure Center_Text (Select_Mode : Byte); + function CharPos (P, Target : Sw_Word) : Sw_Integer; + function CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word; + procedure Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean); + function ClipCopy : Boolean; + procedure ClipCut; + procedure ClipPaste; + procedure DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean); + procedure DoSearchReplace; + procedure DoUpdate; + function Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean; + procedure DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word); + procedure Find; + function GetMousePtr (Mouse : Objects.TPoint) : Sw_Word; + function HasSelection : Boolean; + procedure HideSelect; + procedure Insert_Line (Select_Mode : Byte); + function IsClipboard : Boolean; + procedure Jump_Place_Marker (Element : Byte; Select_Mode : Byte); + procedure Jump_To_Line (Select_Mode : Byte); + function LineEnd (P : Sw_Word) : Sw_Word; + function LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word; + function LineStart (P : Sw_Word) : Sw_Word; + function LineNr (P : Sw_Word) : Sw_Word; + procedure Lock; + function NewLine (Select_Mode : Byte) : Boolean; + function NextChar (P : Sw_Word) : Sw_Word; + function NextLine (P : Sw_Word) : Sw_Word; + function NextWord (P : Sw_Word) : Sw_Word; + function PrevChar (P : Sw_Word) : Sw_Word; + function PrevLine (P : Sw_Word) : Sw_Word; + function PrevWord (P : Sw_Word) : Sw_Word; + procedure Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean); + function Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean; + procedure Remove_EOL_Spaces (Select_Mode : Byte); + procedure Replace; + procedure Scroll_Down; + procedure Scroll_Up; + procedure Select_Word; + procedure SetBufLen (Length : Sw_Word); + procedure Set_Place_Marker (Element : Byte); + procedure Set_Right_Margin; + procedure Set_Tabs; + procedure StartSelect; + procedure Tab_Key (Select_Mode : Byte); + procedure ToggleInsMode; + procedure Unlock; + procedure Update (AFlags : Byte); + procedure Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word); + end; + + TMemoData = record + Length : Sw_Word; + Buffer : TEditBuffer; + end; + + PMemo = ^TMemo; + TMemo = object (TEditor) + constructor Load (var S : Objects.TStream); + function DataSize : Sw_Word; virtual; + procedure GetData (var Rec); virtual; + function GetPalette : PPalette; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure SetData (var Rec); virtual; + procedure Store (var S : Objects.TStream); + end; + + PFileEditor = ^TFileEditor; + TFileEditor = object (TEditor) + FileName : FNameStr; + constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; AFileName : FNameStr); + constructor Load (var S : Objects.TStream); + procedure DoneBuffer; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure InitBuffer; virtual; + function LoadFile : Boolean; + function Save : Boolean; + function SaveAs : Boolean; + function SaveFile : Boolean; + function SetBufSize (NewSize : Sw_Word) : Boolean; virtual; + procedure Store (var S : Objects.TStream); + procedure UpdateCommands; virtual; + function Valid (Command : Word) : Boolean; virtual; + end; + + PEditWindow = ^TEditWindow; + TEditWindow = object (TWindow) + Editor : PFileEditor; + constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer); + constructor Load (var S : Objects.TStream); + procedure Close; virtual; + function GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual; + procedure HandleEvent (var Event : Drivers.TEvent); virtual; + procedure SizeLimits(var Min, Max: TPoint); virtual; + procedure Store (var S : Objects.TStream); + end; + + +function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word; +function CreateFindDialog: PDialog; +function CreateReplaceDialog: PDialog; +function JumpLineDialog : PDialog; +function ReformDocDialog : PDialog; +function RightMarginDialog : PDialog; +function TabStopDialog : Dialogs.PDialog; +function StdEditorDialog(Dialog: Integer; Info: Pointer): Word; + +const + WordChars : set of Char = ['!'..#255]; + + LineBreak : string[2]= +{$ifdef UNIXLF} + #10; +{$else} + #13#10; +{$endif} + + + { The Allow_Reformat boolean is a programmer hook. } + { I've placed this here to allow programmers to } + { determine whether or not paragraph and document } + { reformatting are allowed if Word_Wrap is not } + { active. Some people say don't allow, and others } + { say allow it. I've left it up to the programmer. } + { Set to FALSE if not allowed, or TRUE if allowed. } + Allow_Reformat : Boolean = True; + + EditorDialog : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog; + EditorFlags : Word = efBackupFiles + efPromptOnReplace; + FindStr : String[80] = ''; + ReplaceStr : String[80] = ''; + Clipboard : PEditor = nil; + + ToClipCmds : TCommandSet = ([cmCut,cmCopy,cmClear]); + FromClipCmds : TCommandSet = ([cmPaste]); + UndoCmds : TCommandSet = ([cmUndo,cmRedo]); + +TYPE + TFindDialogRec = packed record + Find : String[80]; + Options : Word; + end; + + TReplaceDialogRec = packed record + Find : String[80]; + Replace : String[80]; + Options : Word; + end; + + TRightMarginRec = packed record + Margin_Position : String[3]; + end; + + TTabStopRec = packed record + Tab_String : String [Tab_Stop_Length]; + end; + +CONST + { VMT constants. } + REditor : TStreamRec = (ObjType : 70; + VmtLink : Ofs (TypeOf (TEditor)^); + Load : @TEditor.Load; + Store : @TEditor.Store); + + RMemo : TStreamRec = (ObjType : 71; + VmtLink : Ofs (TypeOf (TMemo)^); + Load : @TMemo.Load; + Store : @TMemo.Store); + + RFileEditor : TStreamRec = (ObjType : 72; + VmtLink : Ofs (TypeOf (TFileEditor)^); + Load : @TFileEditor.Load; + Store : @TFileEditor.Store); + + RIndicator : TStreamRec = (ObjType : 73; + VmtLink : Ofs (TypeOf (TIndicator)^); + Load : @TIndicator.Load; + Store : @TIndicator.Store); + + REditWindow : TStreamRec = (ObjType : 74; + VmtLink : Ofs (TypeOf (TEditWindow)^); + Load : @TEditWindow.Load; + Store : @TEditWindow.Store); + +procedure RegisterEditors; + + +{**************************************************************************** + Implementation +****************************************************************************} + +implementation + +uses + Memory, Dos, App, StdDlg, MsgBox, Resource; + +type + pword = ^word; + +CONST + { Update flag constants. } + ufUpdate = $01; + ufLine = $02; + ufView = $04; + ufStats = $05; + + { SelectMode constants. } + smExtend = $01; + smDouble = $02; + + sfSearchFailed = NotFoundValue; + + { Arrays that hold all the command keys and options. } + FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A), cmWordLeft, + Ord (^B), cmReformPara, + Ord (^C), cmPageDown, + Ord (^D), cmCharRight, + Ord (^E), cmLineUp, + Ord (^F), cmWordRight, + Ord (^G), cmDelChar, + Ord (^H), cmBackSpace, + Ord (^I), cmTabKey, + Ord (^J), $FF04, + Ord (^K), $FF02, + Ord (^L), cmSearchAgain, + Ord (^M), cmNewLine, + Ord (^N), cmInsertLine, + Ord (^O), $FF03, + Ord (^Q), $FF01, + Ord (^R), cmPageUp, + Ord (^S), cmCharLeft, + Ord (^T), cmDelWord, + Ord (^U), cmUndo, + Ord (^V), cmInsMode, + Ord (^W), cmScrollUp, + Ord (^X), cmLineDown, + Ord (^Y), cmDelLine, + Ord (^Z), cmScrollDown, + kbLeft, cmCharLeft, + kbRight, cmCharRight, + kbCtrlLeft, cmWordLeft, + kbCtrlRight, cmWordRight, + kbHome, cmLineStart, + kbEnd, cmLineEnd, + kbCtrlHome, cmHomePage, + kbCtrlEnd, cmEndPage, + kbUp, cmLineUp, + kbDown, cmLineDown, + kbPgUp, cmPageUp, + kbPgDn, cmPageDown, + kbCtrlPgUp, cmTextStart, + kbCtrlPgDn, cmTextEnd, + kbIns, cmInsMode, + kbDel, cmDelChar, + kbCtrlBack, cmDelStart, + kbShiftIns, cmPaste, + kbShiftDel, cmCut, + kbCtrlIns, cmCopy, + kbCtrlDel, cmClear); + + { SCRLUP - Stop. } { Added ^W to scroll screen up. } + { SCRLDN - Stop. } { Added ^Z to scroll screen down. } + { REFORM - Stop. } { Added ^B for paragraph reformatting. } + { PRETAB - Stop. } { Added ^I for preset tabbing. } + { JLINE - Stop. } { Added ^J to jump to a line number. } + { INSLIN - Stop. } { Added ^N to insert line at cursor. } + { INDENT - Stop. } { Removed ^O and put it into ^QI. } + { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. } + { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH. } + + QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0, + Ord ('1'), cmJumpMark1, + Ord ('2'), cmJumpMark2, + Ord ('3'), cmJumpMark3, + Ord ('4'), cmJumpMark4, + Ord ('5'), cmJumpMark5, + Ord ('6'), cmJumpMark6, + Ord ('7'), cmJumpMark7, + Ord ('8'), cmJumpMark8, + Ord ('9'), cmJumpMark9, + Ord ('A'), cmReplace, + Ord ('C'), cmTextEnd, + Ord ('D'), cmLineEnd, + Ord ('F'), cmFind, + Ord ('H'), cmDelStart, + Ord ('I'), cmIndentMode, + Ord ('L'), cmUndo, + Ord ('R'), cmTextStart, + Ord ('S'), cmLineStart, + Ord ('U'), cmReformDoc, + Ord ('Y'), cmDelEnd); + + { UNDO - Stop. } { Added IDE undo feature of ^QL. } + { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. } + { MARK - Stop. } { Added cmJumpMark# to allow place marking. } + { INDENT - Stop. } { Moved IndentMode here from Firstkeys. } + + BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0, + Ord ('1'), cmSetMark1, + Ord ('2'), cmSetMark2, + Ord ('3'), cmSetMark3, + Ord ('4'), cmSetMark4, + Ord ('5'), cmSetMark5, + Ord ('6'), cmSetMark6, + Ord ('7'), cmSetMark7, + Ord ('8'), cmSetMark8, + Ord ('9'), cmSetMark9, + Ord ('B'), cmStartSelect, + Ord ('C'), cmPaste, + Ord ('D'), cmSave, + Ord ('F'), cmSaveAs, + Ord ('H'), cmHideSelect, + Ord ('K'), cmCopy, + Ord ('S'), cmSave, + Ord ('T'), cmSelectWord, + Ord ('Y'), cmCut, + Ord ('X'), cmSaveDone); + + { SELWRD - Stop. } { Added ^KT to select word only. } + { SAVE - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands. } + { MARK - Stop. } { Added cmSetMark# to allow place marking. } + + FormatKeys : array[0..5 * 2] of Word = (5, Ord ('C'), cmCenterText, + Ord ('T'), cmCenterText, + Ord ('I'), cmSetTabs, + Ord ('R'), cmRightMargin, + Ord ('W'), cmWordWrap); + + { WRAP - Stop. } { Added Wordwrap feature if ^OW pressed. } + { RMSET - Stop. } { Added set right margin feature if ^OR pressed. } + { PRETAB - Stop. } { Added preset tab feature if ^OI pressed. } + { CENTER - Stop. } { Added center text option ^OC for a line. } + + JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine); + + { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. } + + KeyMap : array[0..4] of Pointer = (@FirstKeys, + @QuickKeys, + @BlockKeys, + @FormatKeys, + @JumpKeys); + + { WRAP - Stop. } { Added @FormatKeys for new ^O? keys. } + { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. } + { JLINE - Stop. } { Added @JumpKeys for new ^J? keys. } + { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. } + + +{**************************************************************************** + Dialogs +****************************************************************************} + +function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word; +begin + DefEditorDialog := cmCancel; +end; { DefEditorDialog } + + +function CreateFindDialog: PDialog; +var + D: PDialog; + Control: PView; + R: TRect; +begin + R.Assign(0, 0, 38, 12); + D := New(PDialog, Init(R, strings^.get(sFind))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign(3, 3, 32, 4); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDFindText; + Insert(Control); + R.Assign(2, 2, 15, 3); + Insert(New(PLabel, Init(R, labels^.get(slTextToFind), Control))); + R.Assign(32, 3, 35, 4); + Insert(New(PHistory, Init(R, PInputLine(Control), 10))); + + R.Assign(3, 5, 35, 7); + Control := New(PCheckBoxes, Init(R, + NewSItem (labels^.get(slCaseSensitive), + NewSItem (labels^.get(slWholeWordsOnly),nil)))); + Control^.HelpCtx := hcCCaseSensitive; + Insert(Control); + + R.Assign(14, 9, 24, 11); + Control := New (PButton, Init(R,labels^.get(slOK),cmOk,bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + Inc(R.A.X, 12); Inc(R.B.X, 12); + Control := New (PButton, Init(R,labels^.get(slCancel),cmCancel, bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext(False); + end; + CreateFindDialog := D; +end; + + +function CreateReplaceDialog: PDialog; +var + D: PDialog; + Control: PView; + R: TRect; +begin + R.Assign(0, 0, 40, 16); + D := New(PDialog, Init(R,labels^.get(slReplace))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign(3, 3, 34, 4); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDFindText; + Insert(Control); + R.Assign(2, 2, 15, 3); + Insert(New(PLabel, Init(R,labels^.get(slTextToFind), Control))); + R.Assign(34, 3, 37, 4); + Insert(New(PHistory, Init(R, PInputLine(Control), 10))); + + R.Assign(3, 6, 34, 7); + Control := New(PInputLine, Init(R, 80)); + Control^.HelpCtx := hcDReplaceText; + Insert(Control); + R.Assign(2, 5, 12, 6); + Insert(New(PLabel, Init(R,labels^.get(slNewText), Control))); + R.Assign(34, 6, 37, 7); + Insert(New(PHistory, Init(R, PInputLine(Control), 11))); + + R.Assign(3, 8, 37, 12); + Control := New (Dialogs.PCheckBoxes, Init (R, + NewSItem (labels^.get(slCasesensitive), + NewSItem (labels^.get(slWholewordsonly), + NewSItem (labels^.get(slPromptonreplace), + NewSItem (labels^.get(slReplaceall), nil)))))); + Control^.HelpCtx := hcCCaseSensitive; + Insert (Control); + + R.Assign (8, 13, 18, 15); + Control := New (PButton, Init (R,labels^.get(slOK), cmOk, bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (22, 13, 32, 15); + Control := New (PButton, Init (R,labels^.get(slCancel), cmCancel, bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext(False); + end; + CreateReplaceDialog := D; +end; + + +function JumpLineDialog : PDialog; +VAR + D : PDialog; + R : TRect; + Control: PView; +Begin + R.Assign (0, 0, 26, 8); + D := New(PDialog, Init(R,strings^.get(sJumpTo))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (3, 2, 15, 3); + Control := New (Dialogs.PStaticText, Init (R,labels^.get(slLineNumber))); + Insert (Control); + + R.Assign (15, 2, 21, 3); + Control := New (Dialogs.PInputLine, Init (R, 4)); + Control^.HelpCtx := hcDLineNumber; + Insert (Control); + + R.Assign (21, 2, 24, 3); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12))); + + R.Assign (2, 5, 12, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (14, 5, 24, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + JumpLineDialog := D; +end; { JumpLineDialog } + + +function ReformDocDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that asks where to start reformatting the document. } +VAR + R : TRect; + D : Dialogs.PDialog; + Control : PView; +Begin + R.Assign (0, 0, 32, 11); + D := New (Dialogs.PDialog, Init (R, strings^.get(sReformatDocument))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (2, 2, 30, 3); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSelectWhereToBegin))); + Insert (Control); + + R.Assign (3, 3, 29, 4); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sReformattingTheDocument))); + Insert (Control); + + R.Assign (50, 5, 68, 6); + Control := New (Dialogs.PLabel, Init (R, strings^.get(sReformatDocument), Control)); + Insert (Control); + + R.Assign (5, 5, 26, 7); + Control := New (Dialogs.PRadioButtons, Init (R, + NewSItem (labels^.get(slCurrentLine), + NewSItem (labels^.get(slEntireDocument), Nil)))); + Control^.HelpCtx := hcDReformDoc; + Insert (Control); + + R.Assign (4, 8, 14, 10); + Control := New (Dialogs.PButton, Init (R,labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (17, 8, 27, 10); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + ReformDocDialog := D; +end; { ReformDocDialog } + + +function RightMarginDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that allows the user to change the Right_Margin. } +VAR + R : TRect; + D : PDialog; + Control : PView; +Begin + R.Assign (0, 0, 26, 8); + D := New (Dialogs.PDialog, Init (R, strings^.get(sRightMargin))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (5, 2, 13, 3); + Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSetting))); + Insert (Control); + + R.Assign (13, 2, 18, 3); + Control := New (Dialogs.PInputLine, Init (R, 3)); + Control^.HelpCtx := hcDRightMargin; + Insert (Control); + + R.Assign (18, 2, 21, 3); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13))); + + R.Assign (2, 5, 12, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (14, 5, 24, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + + SelectNext (False); + end; + RightMarginDialog := D; +end; { RightMarginDialog; } + + +function TabStopDialog : Dialogs.PDialog; + { This is a local function that brings up a dialog box } + { that allows the user to set their own tab stops. } +VAR + Index : Sw_Integer; { Local Indexing variable. } + R : TRect; + D : PDialog; + Control : PView; + Tab_Stop : String[2]; { Local string to print tab column number. } +Begin + R.Assign (0, 0, 80, 8); + D := New (Dialogs.PDialog, Init (R, strings^.get(sTabSettings))); + with D^ do + begin + Options := Options or ofCentered; + + R.Assign (2, 2, 77, 3); + Control := New (Dialogs.PStaticText, Init (R, + ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....')); + Insert (Control); + + for Index := 1 to 7 do + begin + R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2); + Str (Index * 10, Tab_Stop); + Control := New (Dialogs.PStaticText, Init (R, Tab_Stop)); + Insert (Control); + end; + + R.Assign (2, 3, 78, 4); + Control := New (Dialogs.PInputLine, Init (R, 74)); + Control^.HelpCtx := hcDTabStops; + Insert (Control); + + R.Assign (38, 5, 41, 6); + Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14))); + + R.Assign (27, 5, 37, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault)); + Control^.HelpCtx := hcDOk; + Insert (Control); + + R.Assign (42, 5, 52, 7); + Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal)); + Control^.HelpCtx := hcDCancel; + Insert (Control); + SelectNext (False); + end; + TabStopDialog := D; +end { TabStopDialog }; + + +function StdEditorDialog(Dialog: Integer; Info: Pointer): Word; +var + R: TRect; + T: TPoint; +begin + case Dialog of + edOutOfMemory: + StdEditorDialog := MessageBox(strings^.get(sOutOfMemory), nil, mfError + mfOkButton); + edReadError: + StdEditorDialog := MessageBox(strings^.get(sFileReadError), @Info, mfError + mfOkButton); + edWriteError: + StdEditorDialog := MessageBox(strings^.get(sFileWriteError), @Info, mfError + mfOkButton); + edCreateError: + StdEditorDialog := MessageBox(strings^.get(sFileCreateError), @Info, mfError + mfOkButton); + edSaveModify: + StdEditorDialog := MessageBox(strings^.get(sModified), @Info, mfInformation + mfYesNoCancel); + edSaveUntitled: + StdEditorDialog := MessageBox(strings^.get(sFileUntitled), nil, mfInformation + mfYesNoCancel); + edSaveAs: + StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*', + labels^.get(slSaveFileAs), labels^.get(slName), fdOkButton, 101)), Info); + edFind: + StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info); + edSearchFailed: + StdEditorDialog := MessageBox(strings^.get(sSearchStringNotFound), nil, mfError + mfOkButton); + edReplace: + StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info); + edReplacePrompt: + begin + { Avoid placing the dialog on the same line as the cursor } + R.Assign(0, 1, 40, 8); + R.Move((Desktop^.Size.X - R.B.X) div 2, 0); + Desktop^.MakeGlobal(R.B, T); + Inc(T.Y); + if PPoint(Info)^.Y <= T.Y then + R.Move(0, Desktop^.Size.Y - R.B.Y - 2); + StdEditorDialog := MessageBoxRect(R, strings^.get(sReplaceThisOccurence), + nil, mfYesNoCancel + mfInformation); + end; + edJumpToLine: + StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info); + edSetTabStops: + StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info); + edPasteNotPossible: + StdEditorDialog := MessageBox (strings^.get(sPasteNotPossible), nil, mfError + mfOkButton); + edReformatDocument: + StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info); + edReformatNotAllowed: + StdEditorDialog := MessageBox (strings^.get(sWordWrapOff), nil, mfError + mfOkButton); + edReformNotPossible: + StdEditorDialog := MessageBox (strings^.get(sReformatNotPossible), nil, mfError + mfOkButton); + edReplaceNotPossible: + StdEditorDialog := MessageBox (strings^.get(sReplaceNotPossible), nil, mfError + mfOkButton); + edRightMargin: + StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info); + edWrapNotPossible: + StdEditorDialog := MessageBox (strings^.get(sWordWrapNotPossible), nil, mfError + mfOKButton); + else + StdEditorDialog := MessageBox (strings^.get(sUnknownDialog), nil, mfError + mfOkButton); + end; +end; + + +{**************************************************************************** + Helpers +****************************************************************************} + +function CountLines(var Buf; Count: sw_Word): sw_Integer; +var + p : pchar; + lines : sw_word; +begin + p:=pchar(@buf); + lines:=0; + while (count>0) do + begin + if p^ in [#10,#13] then + begin + inc(lines); + if ord((p+1)^)+ord(p^)=23 then + begin + inc(p); + dec(count); + if count=0 then + break; + end; + end; + inc(p); + dec(count); + end; + CountLines:=Lines; +end; + + +procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint); +{ Get the limits needed for Buf, its an extended version of countlines (lim.y), + which also gets the maximum line length in lim.x } +var + p : pchar; + len : sw_word; +begin + lim.x:=0; + lim.y:=0; + len:=0; + p:=pchar(@buf); + while (count>0) do + begin + if p^ in [#10,#13] then + begin + if len>lim.x then + lim.x:=len; + inc(lim.y); + if ord((p+1)^)+ord(p^)=23 then + begin + inc(p); + dec(count); + end; + len:=0; + end + else + inc(len); + inc(p); + dec(count); + end; +end; + + +function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word; +var + p : pword; + count : sw_word; +begin + p:=keymap; + count:=p^; + inc(p); + while (count>0) do + begin + if (lo(p^)=lo(keycode)) and + ((hi(p^)=0) or (hi(p^)=hi(keycode))) then + begin + inc(p); + scankeymap:=p^; + exit; + end; + inc(p,2); + dec(count); + end; + scankeymap:=0; +end; + + +Type + Btable = Array[0..255] of Byte; +Procedure BMMakeTable(const s:string; Var t : Btable); +{ Makes a Boyer-Moore search table. s = the search String t = the table } +Var + x : sw_integer; +begin + FillChar(t,sizeof(t),length(s)); + For x := length(s) downto 1 do + if (t[ord(s[x])] = length(s)) then + t[ord(s[x])] := length(s) - x; +end; + + +function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word; +Var + buffer : Array[0..MaxBufLength-1] of Byte Absolute block; + s2 : String; + len, + numb : Sw_Word; + found : Boolean; + bt : Btable; +begin + BMMakeTable(str,bt); + len:=length(str); + s2[0]:=chr(len); { sets the length to that of the search String } + found:=False; + numb:=pred(len); + While (not found) and (numb<(size-len)) do + begin + { partial match } + if buffer[numb] = ord(str[len]) then + begin + { less partial! } + if buffer[numb-pred(len)] = ord(str[1]) then + begin + move(buffer[numb-pred(len)],s2[1],len); + if (str=s2) then + begin + found:=true; + break; + end; + end; + inc(numb); + end + else + inc(numb,Bt[buffer[numb]]); + end; + if not found then + Scan := NotFoundValue + else + Scan := numb - pred(len); +end; + + +function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word; +Var + buffer : Array[0..MaxBufLength-1] of Char Absolute block; + s : String; + len, + numb, + x : Sw_Word; + found : Boolean; + bt : Btable; + p : pchar; + c : char; +begin + len:=length(str); + { create uppercased string } + s[0]:=chr(len); + for x:=1to len do + begin + if str[x] in ['a'..'z'] then + s[x]:=chr(ord(str[x])-32) + else + s[x]:=str[x]; + end; + BMMakeTable(s,bt); + found:=False; + numb:=pred(len); + While (not found) and (numb<(size-len)) do + begin + { partial match } + c:=buffer[numb]; + if c in ['a'..'z'] then + c:=chr(ord(c)-32); + if (c=s[len]) then + begin + { less partial! } + p:=@buffer[numb-pred(len)]; + x:=1; + while (x<=len) do + begin + if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or + (p^=s[x])) then + break; + inc(p); + inc(x); + end; + if (x>len) then + begin + found:=true; + break; + end; + inc(numb); + end + else + inc(numb,Bt[ord(c)]); + end; + if not found then + IScan := NotFoundValue + else + IScan := numb - pred(len); +end; + + +{**************************************************************************** + TIndicator +****************************************************************************} + +constructor TIndicator.Init (var Bounds : TRect); +begin + Inherited Init (Bounds); + GrowMode := gfGrowLoY + gfGrowHiY; +end; { TIndicator.Init } + + +procedure TIndicator.Draw; +VAR + Color : Byte; + Frame : Char; + L : array[0..1] of Longint; + S : String[15]; + B : TDrawBuffer; +begin + if State and sfDragging = 0 then + begin + Color := GetColor (1); + Frame := #205; + end + else + begin + Color := GetColor (2); + Frame := #196; + end; + MoveChar (B, Frame, Color, Size.X); + { If the text has been modified, put an 'M' in the TIndicator display. } + if Modified then + WordRec (B[1]).Lo := 77; + { If WordWrap is active put a 'W' in the TIndicator display. } + if WordWrap then + WordRec (B[2]).Lo := 87 + else + WordRec (B[2]).Lo := Byte (Frame); + { If AutoIndent is active put an 'I' in TIndicator display. } + if AutoIndent then + WordRec (B[0]).Lo := 73 + else + WordRec (B[0]).Lo := Byte (Frame); + L[0] := Location.Y + 1; + L[1] := Location.X + 1; + FormatStr (S, ' %d:%d ', L); + MoveStr (B[9 - Pos (':', S)], S, Color); { Changed original 8 to 9. } + WriteBuf (0, 0, Size.X, 1, B); +end; { TIndicator.Draw } + + +function TIndicator.GetPalette : PPalette; +const + P : string[Length (CIndicator)] = CIndicator; +begin + GetPalette := @P; +end; { TIndicator.GetPalette } + + +procedure TIndicator.SetState (AState : Word; Enable : Boolean); +begin + Inherited SetState (AState, Enable); + if AState = sfDragging then + DrawView; +end; { TIndicator.SetState } + + +procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean; + IsModified : Boolean; + IsWordWrap : Boolean); +begin + if (Location.X<>ALocation.X) or + (Location.Y<>ALocation.Y) or + (AutoIndent <> IsAutoIndent) or + (Modified <> IsModified) or + (WordWrap <> IsWordWrap) then + begin + Location := ALocation; + AutoIndent := IsAutoIndent; { Added provisions to show AutoIndent. } + Modified := IsModified; + WordWrap := IsWordWrap; { Added provisions to show WordWrap. } + DrawView; + end; +end; { TIndicator.SetValue } + + +{**************************************************************************** + TLineInfo +****************************************************************************} + +constructor TLineInfo.Init; +begin + MaxPos:=0; + Grow(1); +end; + + +destructor TLineInfo.Done; +begin + FreeMem(Info,MaxPos*sizeof(TLineInfoRec)); +end; + + +procedure TLineInfo.Grow(pos:Sw_word); +var + NewSize : Sw_word; + P : pointer; +begin + NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow)); + GetMem(P,NewSize*sizeof(TLineInfoRec)); + FillChar(P^,NewSize*sizeof(TLineInfoRec),0); + Move(Info^,P^,MaxPos*sizeof(TLineInfoRec)); + Freemem(Info,MaxPos*sizeof(TLineInfoRec)); + Info:=P; +end; + + +procedure TLineInfo.SetLen(pos,val:Sw_Word); +begin + if pos>=MaxPos then + Grow(Pos); + Info^[Pos].Len:=val +end; + + +procedure TLineInfo.SetAttr(pos,val:Sw_Word); +begin + if pos>=MaxPos then + Grow(Pos); + Info^[Pos].Attr:=val +end; + + +function TLineInfo.GetLen(pos:Sw_Word):Sw_Word; +begin + GetLen:=Info^[Pos].Len; +end; + + +function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word; +begin + GetAttr:=Info^[Pos].Attr; +end; + + + +{**************************************************************************** + TEditor +****************************************************************************} + +constructor TEditor.Init (var Bounds : TRect; + AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; ABufSize : Sw_Word); +var + Element : Byte; { Place_Marker array element to initialize array with. } +begin + Inherited Init (Bounds); + GrowMode := gfGrowHiX + gfGrowHiY; + Options := Options or ofSelectable; + Flags := EditorFlags; + EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast; + ShowCursor; + + HScrollBar := AHScrollBar; + VScrollBar := AVScrollBar; + + Indicator := AIndicator; + BufSize := ABufSize; + CanUndo := True; + InitBuffer; + + if assigned(Buffer) then + IsValid := True + else + begin + EditorDialog (edOutOfMemory, nil); + BufSize := 0; + end; + + SetBufLen (0); + + for Element := 1 to 10 do + Place_Marker[Element] := 0; + + Element := 1; + while Element <= 70 do + begin + if Element mod 5 = 0 then + Insert ('x', Tab_Settings, Element) + else + Insert (#32, Tab_Settings, Element); + Inc (Element); + end; + { Default Right_Margin value. Change it if you want another. } + Right_Margin := 76; + TabSize:=8; +end; { TEditor.Init } + + +constructor TEditor.Load (var S : Objects.TStream); +begin + Inherited Load (S); + GetPeerViewPtr (S, HScrollBar); + GetPeerViewPtr (S, VScrollBar); + GetPeerViewPtr (S, Indicator); + S.Read (BufSize, SizeOf (Sw_Word)); + S.Read (CanUndo, SizeOf (Boolean)); + S.Read (AutoIndent, SizeOf (AutoIndent)); + S.Read (Line_Number, SizeOf (Line_Number)); + S.Read (Place_Marker, SizeOf (Place_Marker)); + S.Read (Right_Margin, SizeOf (Right_Margin)); + S.Read (Tab_Settings, SizeOf (Tab_Settings)); + S.Read (Word_Wrap, SizeOf (Word_Wrap)); + InitBuffer; + if Assigned(Buffer) then + IsValid := True + else + begin + EditorDialog (edOutOfMemory, nil); + BufSize := 0; + end; + Lock; + SetBufLen (0); +end; { TEditor.Load } + + +destructor TEditor.Done; +begin + DoneBuffer; + Inherited Done; +end; { TEditor.Done } + + +function TEditor.BufChar(P: Sw_Word): Char; +begin + if P>=CurPtr then + inc(P,Gaplen); + BufChar:=Buffer^[P]; +end; + + +function TEditor.BufPtr(P: Sw_Word): Sw_Word; +begin + if P>=CurPtr then + BufPtr:=P+GapLen + else + BufPtr:=P; +end; + + +procedure TEditor.Center_Text (Select_Mode : Byte); +{ This procedure will center the current line of text. } +{ Centering is based on the current Right_Margin. } +{ If the Line_Length exceeds the Right_Margin, or the } +{ line is just a blank line, we exit and do nothing. } +VAR + Spaces : array [1..80] of Char; { Array to hold spaces we'll insert. } + Index : Byte; { Index into Spaces array. } + Line_Length : Sw_Integer; { Holds the length of the line. } + E,S : Sw_Word; { End of the current line. } +begin + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { If the line is blank (only a CR/LF on it) then do noting. } + if E = S then + Exit; + { Set CurPtr to start of line. Check if line begins with a space. } + { We must strip out any spaces from the beginning, or end of lines. } + { If line does not start with space, make sure line length does not } + { exceed the Right_Margin. If it does, then do nothing. } + SetCurPtr (S, Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if Buffer^[CurPtr] = #32 then + begin + { If the next word is greater than the end of line then do nothing. } + { If the line length is greater than Right_Margin then do nothing. } + { Otherwise, delete all spaces at the start of line. } + { Then reset end of line and put CurPtr at start of modified line. } + E := LineEnd (CurPtr); + if NextWord (CurPtr) > E then + Exit; + if E - NextWord (CurPtr) > Right_Margin then + Exit; + DeleteRange (CurPtr, NextWord (CurPtr), True); + E := LineEnd (CurPtr); + SetCurPtr (LineStart (CurPtr), Select_Mode); + end + else + if E - CurPtr > Right_Margin then + Exit; + { Now we determine the real length of the line. } + { Then we subtract the Line_Length from Right_Margin. } + { Dividing the result by two tells us how many spaces } + { must be inserted at start of line to center it. } + { When we're all done, set the CurPtr to end of line. } + Line_Length := E - CurPtr; + for Index := 1 to ((Right_Margin - Line_Length) shr 1) do + Spaces[Index] := #32; + InsertText (@Spaces, Index, False); + SetCurPtr (LineEnd (CurPtr), Select_Mode); +end; { TEditor.Center_Text } + + +procedure TEditor.ChangeBounds (var Bounds : TRect); +begin + SetBounds (Bounds); + Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X)); + Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y)); + Update (ufView); +end; { TEditor.ChangeBounds } + + +function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer; +VAR + Pos : Sw_Integer; +begin + Pos := 0; + while P < Target do + begin + if BufChar (P) = #9 then + Pos := Pos or 7; + Inc (Pos); + Inc (P); + end; + CharPos := Pos; +end; { TEditor.CharPos } + + +function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word; +VAR + Pos : Sw_Integer; +begin + Pos := 0; + while (Pos < Target) and (P < BufLen) and not(BufChar (P) in [#10,#13]) do + begin + if BufChar (P) = #9 then + Pos := Pos or 7; + Inc (Pos); + Inc (P); + end; + if Pos > Target then + Dec (P); + CharPtr := P; +end; { TEditor.CharPtr } + + +procedure TEditor.Check_For_Word_Wrap (Select_Mode : Byte; + Center_Cursor : Boolean); +{ This procedure checks if CurPos.X > Right_Margin. } +{ If it is, then we Do_Word_Wrap. Simple, eh? } +begin + if CurPos.X > Right_Margin then + Do_Word_Wrap (Select_Mode, Center_Cursor); +end; {Check_For_Word_Wrap} + + +function TEditor.ClipCopy : Boolean; +begin + ClipCopy := False; + if Assigned(Clipboard) and (Clipboard <> @Self) then + begin + ClipCopy := Clipboard^.InsertFrom (@Self); + Selecting := False; + Update (ufUpdate); + end; +end; { TEditor.ClipCopy } + + +procedure TEditor.ClipCut; +begin + if ClipCopy then + begin + Update_Place_Markers (0, + Self.SelEnd - Self.SelStart, + Self.SelStart, + Self.SelEnd); + DeleteSelect; + end; +end; { TEditor.ClipCut } + + +procedure TEditor.ClipPaste; +begin + if Assigned(Clipboard) and (Clipboard <> @Self) then + begin + { Do not allow paste operations that will exceed } + { the Right_Margin when Word_Wrap is active and } + { cursor is at EOL. } + if Word_Wrap and (CurPos.X > Right_Margin) then + begin + EditorDialog (edPasteNotPossible, nil); + Exit; + end; + { The editor will not copy selected text if the CurPtr } + { is not the same value as the SelStart. However, it } + { does return an InsCount. This may, or may not, be a } + { bug. We don't want to update the Place_Marker if } + { there's no text copied. } + if CurPtr = SelStart then + Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart, + 0, + Clipboard^.SelStart, + Clipboard^.SelEnd); + InsertFrom (Clipboard); + end; +end; { TEditor.ClipPaste } + + +procedure TEditor.ConvertEvent (var Event : Drivers.TEvent); +VAR + ShiftState : Byte; + Key : Word; +begin + ShiftState:=GetShiftState; + if Event.What = evKeyDown then + begin + if (ShiftState and $03 <> 0) + and (Event.ScanCode >= $47) + and (Event.ScanCode <= $51) then + Event.CharCode := #0; + Key := Event.KeyCode; + if KeyState <> 0 then + begin + if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then + Inc (Key, $40); + if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then + Dec (Key, $20); + end; + Key := ScanKeyMap (KeyMap[KeyState], Key); + KeyState := 0; + if Key <> 0 then + if Hi (Key) = $FF then + begin + KeyState := Lo (Key); + ClearEvent (Event); + end + else + begin + Event.What := evCommand; + Event.Command := Key; + end; + end; +end; { TEditor.ConvertEvent } + + +function TEditor.CursorVisible : Boolean; +begin + CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y); +end; { TEditor.CursorVisible } + + +procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean); +begin + { This will update Place_Marker for all deletions. } + { EXCEPT the Remove_EOL_Spaces deletion. } + Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr); + if HasSelection and DelSelect then + DeleteSelect + else + begin + SetSelect (CurPtr, EndPtr, True); + DeleteSelect; + SetSelect (StartPtr, CurPtr, False); + DeleteSelect; + end; +end; { TEditor.DeleteRange } + + +procedure TEditor.DeleteSelect; +begin + InsertText (nil, 0, False); +end; { TEditor.DeleteSelect } + + +procedure TEditor.DoneBuffer; +begin + if assigned(Buffer) then + begin + FreeMem (Buffer, BufSize); + Buffer := nil; + end; +end; { TEditor.DoneBuffer } + + +procedure TEditor.DoSearchReplace; +VAR + I : Sw_Word; + C : Objects.TPoint; +begin + repeat + I := cmCancel; + if not Search (FindStr, Flags) then + begin + if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then + EditorDialog (edSearchFailed, nil) + end + else + if Flags and efDoReplace <> 0 then + begin + I := cmYes; + if Flags and efPromptOnReplace <> 0 then + begin + MakeGlobal (Cursor, C); + I := EditorDialog (edReplacePrompt, Pointer(@C)); + end; + if I = cmYes then + begin + { If Word_Wrap is active and we are at EOL } + { disallow replace by bringing up a dialog } + { stating that replace is not possible. } + if Word_Wrap and + ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then + EditorDialog (edReplaceNotPossible, nil) + else + begin + Lock; + Search_Replace := True; + if length (ReplaceStr) < length (FindStr) then + Update_Place_Markers (0, + Length (FindStr) - Length (ReplaceStr), + CurPtr - Length (FindStr) + Length (ReplaceStr), + CurPtr) + else + if length (ReplaceStr) > length (FindStr) then + Update_Place_Markers (Length (ReplaceStr) - Length (FindStr), + 0, + CurPtr, + CurPtr + (Length (ReplaceStr) - Length (FindStr))); + InsertText (@ReplaceStr[1], Length (ReplaceStr), False); + Search_Replace := False; + TrackCursor (False); + Unlock; + end; + end; + end; + until (I = cmCancel) or (Flags and efReplaceAll = 0); +end; { TEditor.DoSearchReplace } + + +procedure TEditor.DoUpdate; +begin + if UpdateFlags <> 0 then + begin + SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y); + if UpdateFlags and ufView <> 0 then + DrawView + else + if UpdateFlags and ufLine <> 0 then + DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr)); + if assigned(HScrollBar) then + HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1); + if assigned(VScrollBar) then + VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1); + if assigned(Indicator) then + Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap); + if State and sfActive <> 0 then + UpdateCommands; + UpdateFlags := 0; + end; +end; { TEditor.DoUpdate } + + +function TEditor.Do_Word_Wrap (Select_Mode : Byte; + Center_Cursor : Boolean) : Boolean; +{ This procedure does the actual wordwrap. It always assumes the CurPtr } +{ is at Right_Margin + 1. It makes several tests for special conditions } +{ and processes those first. If they all fail, it does a normal wrap. } +VAR + A : Sw_Word; { Distance between line start and first word on line. } + C : Sw_Word; { Current pointer when we come into procedure. } + L : Sw_Word; { BufLen when we come into procedure. } + P : Sw_Word; { Position of pointer at any given moment. } + S : Sw_Word; { Start of a line. } +begin + Do_Word_Wrap := False; + Select_Mode := 0; + if BufLen >= (BufSize - 1) then + exit; + C := CurPtr; + L := BufLen; + S := LineStart (CurPtr); + { If first character in the line is a space and autoindent mode is on } + { then we check to see if NextWord(S) exceeds the CurPtr. If it does, } + { we set CurPtr as the AutoIndent marker. If it doesn't, we will set } + { NextWord(S) as the AutoIndent marker. If neither, we set it to S. } + if AutoIndent and (Buffer^[S] = ' ') then + begin + if NextWord (S) > CurPtr then + A := CurPtr + else + A := NextWord (S); + end + else + A := NextWord (S); + { Though NewLine will remove EOL spaces, we do it here too. } + { This catches the instance where a user may try to space } + { completely across the line, in which case CurPtr.X = 0. } + Remove_EOL_Spaces (Select_Mode); + if CurPos.X = 0 then + begin + NewLine (Select_Mode); + Do_Word_Wrap := True; + Exit; + end; + { At this point we have one of five situations: } + { } + { 1) AutoIndent is on and this line is all spaces before CurPtr. } + { 2) AutoIndent is off and this line is all spaces before CurPtr. } + { 3) AutoIndent is on and this line is continuous characters before CurPtr. } + { 4) AutoIndent is off and this line is continuous characters before CurPtr. } + { 5) This is just a normal line of text. } + { } + { Conditions 1 through 4 have to be taken into account before condition 5. } + { First, we see if there are all spaces and/or all characters. } + { Then we determine which one it really is. Finally, we take } + { a course of action based on the state of AutoIndent. } + if PrevWord (CurPtr) <= S then + begin + P := CurPtr - 1; + while ((Buffer^[P] <> ' ') and (P > S)) do + Dec (P); + { We found NO SPACES. Conditions 4 and 5 are treated the same. } + { We can NOT do word wrap and put up a dialog box stating such. } + { Delete character just entered so we don't exceed Right_Margin. } + if P = S then + begin + EditorDialog (edWrapNotPossible, nil); + DeleteRange (PrevChar (CurPtr), CurPtr, True); + Exit; + end + else + begin + { There are spaces. Now find out if they are all spaces. } + { If so, see if AutoIndent is on. If it is, turn it off, } + { do a NewLine, and turn it back on. Otherwise, just do } + { the NewLine. We go through all of these gyrations for } + { AutoIndent. Being way out here with a preceding line } + { of spaces and wrapping with AutoIndent on is real dumb! } + { However, the user expects something. The wrap will NOT } + { autoindent, but they had no business being here anyway! } + P := CurPtr - 1; + while ((Buffer^[P] = ' ') and (P > S)) do + Dec (P); + if P = S then + begin + if Autoindent then + begin + AutoIndent := False; + NewLine (Select_Mode); + AutoIndent := True; + end + else + NewLine (Select_Mode); + end; { AutoIndent } + end; { P = S for spaces } + end { P = S for no spaces } + else { PrevWord (CurPtr) <= S } + begin + { Hooray! We actually had a plain old line of text to wrap! } + { Regardless if we are pushing out a line beyond the Right_Margin, } + { or at the end of a line itself, the following will determine } + { exactly where to do the wrap and re-set the cursor accordingly. } + { However, if P = A then we can't wrap. Show dialog and exit. } + P := CurPtr; + while P - S > Right_Margin do + P := PrevWord (P); + if (P = A) then + begin + EditorDialog (edReformNotPossible, nil); + SetCurPtr (P, Select_Mode); + Exit; + end; + SetCurPtr (P, Select_Mode); + NewLine (Select_Mode); + end; { PrevWord (CurPtr <= S } + { Track the cursor here (it is at CurPos.X = 0) so the view } + { will redraw itself at column 0. This eliminates having it } + { redraw starting at the current cursor and not being able } + { to see text before the cursor. Of course, we also end up } + { redrawing the view twice, here and back in HandleEvent. } + { } + { Reposition cursor so user can pick up where they left off. } + TrackCursor (Center_Cursor); + SetCurPtr (C - (L - BufLen), Select_Mode); + Do_Word_Wrap := True; +end; { TEditor.Do_Word_Wrap } + + +procedure TEditor.Draw; +begin + if DrawLine <> Delta.Y then + begin + DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine); + DrawLine := Delta.Y; + end; + DrawLines (0, Size.Y, DrawPtr); +end; { TEditor.Draw } + + +procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word); +VAR + Color : Word; + B : array[0..MaxLineLength - 1] of Sw_Word; +begin + Color := GetColor ($0201); + while Count > 0 do + begin + FormatLine (B, LinePtr, Delta.X + Size.X, Color); + WriteBuf (0, Y, Size.X, 1, B[Delta.X]); + LinePtr := NextLine (LinePtr); + Inc (Y); + Dec (Count); + end; +end; { TEditor.DrawLines } + + +procedure TEditor.Find; +VAR + FindRec : TFindDialogRec; +begin + with FindRec do + begin + Find := FindStr; + Options := Flags; + if EditorDialog (edFind, @FindRec) <> cmCancel then + begin + FindStr := Find; + Flags := Options and not efDoReplace; + DoSearchReplace; + end; + end; +end; { TEditor.Find } + + +procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word; + Width : Sw_Integer; + Colors : Word); +var + outptr : pword; + outcnt, + idxpos : Sw_Word; + attr : Word; + + procedure FillSpace(i:Sw_Word); + var + w : word; + begin + inc(OutCnt,i); + w:=32 or attr; + while (i>0) do + begin + OutPtr^:=w; + inc(OutPtr); + dec(i); + end; + end; + + function FormatUntil(endpos:Sw_word):boolean; + var + p : pchar; + begin + FormatUntil:=false; + p:=pchar(Buffer)+idxpos; + while endpos>idxpos do + begin + if OutCnt>=Width then + exit; + case p^ of + #9 : + FillSpace(Tabsize-(outcnt mod Tabsize)); + #10,#13 : + begin + FillSpace(Width-OutCnt); + FormatUntil:=true; + exit; + end; + else + begin + inc(OutCnt); + OutPtr^:=ord(p^) or attr; + inc(OutPtr); + end; + end; { case } + inc(p); + inc(idxpos); + end; + end; + +begin + OutCnt:=0; + OutPtr:=@DrawBuf; + idxPos:=LinePtr; + attr:=lo(Colors) shl 8; + if FormatUntil(SelStart) then + exit; + attr:=hi(Colors) shl 8; + if FormatUntil(CurPtr) then + exit; + inc(idxPos,GapLen); + if FormatUntil(SelEnd+GapLen) then + exit; + attr:=lo(Colors) shl 8; + if FormatUntil(BufSize) then + exit; +{ fill up until width } + FillSpace(Width-OutCnt); +end; {TEditor.FormatLine} + + +function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word; +begin + MakeLocal (Mouse, Mouse); + Mouse.X := Max (0, Min (Mouse.X, Size.X - 1)); + Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1)); + GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine), + Mouse.X + Delta.X); +end; { TEditor.GetMousePtr } + + +function TEditor.GetPalette : PPalette; +CONST + P : String[Length (CEditor)] = CEditor; +begin + GetPalette := @P; +end; { TEditor.GetPalette } + + +procedure TEditor.HandleEvent (var Event : Drivers.TEvent); +VAR + ShiftState : Byte; + CenterCursor : Boolean; + SelectMode : Byte; + D : Objects.TPoint; + Mouse : Objects.TPoint; + + function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean; + begin + CheckScrollBar := FALSE; + if (Event.InfoPtr = P) and (P^.Value <> D) then + begin + D := P^.Value; + Update (ufView); + CheckScrollBar := TRUE; + end; + end; {CheckScrollBar} + +begin + Inherited HandleEvent (Event); + ConvertEvent (Event); + CenterCursor := not CursorVisible; + SelectMode := 0; + ShiftState:=GetShiftState; + if Selecting or (ShiftState and $03 <> 0) then + SelectMode := smExtend; + case Event.What of + Drivers.evMouseDown: + begin + if Event.Double then + SelectMode := SelectMode or smDouble; + repeat + Lock; + if Event.What = evMouseAuto then + begin + MakeLocal (Event.Where, Mouse); + D := Delta; + if Mouse.X < 0 then + Dec (D.X); + if Mouse.X >= Size.X then + Inc (D.X); + if Mouse.Y < 0 then + Dec (D.Y); + if Mouse.Y >= Size.Y then + Inc (D.Y); + ScrollTo (D.X, D.Y); + end; + SetCurPtr (GetMousePtr (Event.Where), SelectMode); + SelectMode := SelectMode or smExtend; + Unlock; + until not MouseEvent (Event, evMouseMove + evMouseAuto); + end; { Drivers.evMouseDown } + + Drivers.evKeyDown: + case Event.CharCode of + #32..#255: + begin + Lock; + if Overwrite and not HasSelection then + if CurPtr <> LineEnd (CurPtr) then + SelEnd := NextChar (CurPtr); + InsertText (@Event.CharCode, 1, False); + if Word_Wrap then + Check_For_Word_Wrap (SelectMode, CenterCursor); + TrackCursor (CenterCursor); + Unlock; + end; + + else + Exit; + end; { Drivers.evKeyDown } + + Drivers.evCommand: + case Event.Command of + cmFind : Find; + cmReplace : Replace; + cmSearchAgain : DoSearchReplace; + else + begin + Lock; + case Event.Command of + cmCut : ClipCut; + cmCopy : ClipCopy; + cmPaste : ClipPaste; + cmUndo : Undo; + cmClear : DeleteSelect; + cmCharLeft : SetCurPtr (PrevChar (CurPtr), SelectMode); + cmCharRight : SetCurPtr (NextChar (CurPtr), SelectMode); + cmWordLeft : SetCurPtr (PrevWord (CurPtr), SelectMode); + cmWordRight : SetCurPtr (NextWord (CurPtr), SelectMode); + cmLineStart : SetCurPtr (LineStart (CurPtr), SelectMode); + cmLineEnd : SetCurPtr (LineEnd (CurPtr), SelectMode); + cmLineUp : SetCurPtr (LineMove (CurPtr, -1), SelectMode); + cmLineDown : SetCurPtr (LineMove (CurPtr, 1), SelectMode); + cmPageUp : SetCurPtr (LineMove (CurPtr, - (Size.Y - 1)), SelectMode); + cmPageDown : SetCurPtr (LineMove (CurPtr, Size.Y - 1), SelectMode); + cmTextStart : SetCurPtr (0, SelectMode); + cmTextEnd : SetCurPtr (BufLen, SelectMode); + cmNewLine : NewLine (SelectMode); + cmBackSpace : DeleteRange (PrevChar (CurPtr), CurPtr, True); + cmDelChar : DeleteRange (CurPtr, NextChar (CurPtr), True); + cmDelWord : DeleteRange (CurPtr, NextWord (CurPtr), False); + cmDelStart : DeleteRange (LineStart (CurPtr), CurPtr, False); + cmDelEnd : DeleteRange (CurPtr, LineEnd (CurPtr), False); + cmDelLine : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False); + cmInsMode : ToggleInsMode; + cmStartSelect : StartSelect; + cmHideSelect : HideSelect; + cmIndentMode : begin + AutoIndent := not AutoIndent; + Update (ufStats); + end; { Added provision to update TIndicator if ^QI pressed. } + cmCenterText : Center_Text (SelectMode); + cmEndPage : SetCurPtr (LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode); + cmHomePage : SetCurPtr (LineMove (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode); + cmInsertLine : Insert_Line (SelectMode); + cmJumpLine : Jump_To_Line (SelectMode); + cmReformDoc : Reformat_Document (SelectMode, CenterCursor); + cmReformPara : Reformat_Paragraph (SelectMode, CenterCursor); + cmRightMargin : Set_Right_Margin; + cmScrollDown : Scroll_Down; + cmScrollUp : Scroll_Up; + cmSelectWord : Select_Word; + cmSetTabs : Set_Tabs; + cmTabKey : Tab_Key (SelectMode); + cmWordWrap : begin + Word_Wrap := not Word_Wrap; + Update (ufStats); + end; { Added provision to update TIndicator if ^OW pressed. } + cmSetMark0 : Set_Place_Marker (10); + cmSetMark1 : Set_Place_Marker (1); + cmSetMark2 : Set_Place_Marker (2); + cmSetMark3 : Set_Place_Marker (3); + cmSetMark4 : Set_Place_Marker (4); + cmSetMark5 : Set_Place_Marker (5); + cmSetMark6 : Set_Place_Marker (6); + cmSetMark7 : Set_Place_Marker (7); + cmSetMark8 : Set_Place_Marker (8); + cmSetMark9 : Set_Place_Marker (9); + cmJumpMark0 : Jump_Place_Marker (10, SelectMode); + cmJumpMark1 : Jump_Place_Marker (1, SelectMode); + cmJumpMark2 : Jump_Place_Marker (2, SelectMode); + cmJumpMark3 : Jump_Place_Marker (3, SelectMode); + cmJumpMark4 : Jump_Place_Marker (4, SelectMode); + cmJumpMark5 : Jump_Place_Marker (5, SelectMode); + cmJumpMark6 : Jump_Place_Marker (6, SelectMode); + cmJumpMark7 : Jump_Place_Marker (7, SelectMode); + cmJumpMark8 : Jump_Place_Marker (8, SelectMode); + cmJumpMark9 : Jump_Place_Marker (9, SelectMode); + else + Unlock; + Exit; + end; { Event.Command (Inner) } + TrackCursor (CenterCursor); + { If the user presses any key except cmNewline or cmBackspace } + { we need to check if the file has been modified yet. There } + { can be no spaces at the end of a line, or wordwrap doesn't } + { work properly. We don't want to do this if the file hasn't } + { been modified because the user could be bringing in an ASCII } + { file from an editor that allows spaces at the EOL. If we } + { took them out in that scenario the "M" would appear on the } + { TIndicator line and the user would get upset or confused. } + if (Event.Command <> cmNewLine) and + (Event.Command <> cmBackSpace) and + (Event.Command <> cmTabKey) and + Modified then + Remove_EOL_Spaces (SelectMode); + Unlock; + end; { Event.Command (Outer) } + end; { Drivers.evCommand } + + Drivers.evBroadcast: + case Event.Command of + cmScrollBarChanged: + if (Event.InfoPtr = HScrollBar) or + (Event.InfoPtr = VScrollBar) then + begin + CheckScrollBar (HScrollBar, Delta.X); + CheckScrollBar (VScrollBar, Delta.Y); + end + else + exit; + else + Exit; + end; { Drivers.evBroadcast } + + end; + ClearEvent (Event); +end; { TEditor.HandleEvent } + + +function TEditor.HasSelection : Boolean; +begin + HasSelection := SelStart <> SelEnd; +end; { TEditor.HasSelection } + + +procedure TEditor.HideSelect; +begin + Selecting := False; + SetSelect (CurPtr, CurPtr, False); +end; { TEditor.HideSelect } + + +procedure TEditor.InitBuffer; +begin + Buffer := MemAlloc (BufSize); +end; { TEditor.InitBuffer } + + +function TEditor.InsertBuffer (var P : PEditBuffer; + Offset, Length : Sw_Word; + AllowUndo, SelectText : Boolean) : Boolean; +VAR + SelLen : Sw_Word; + DelLen : Sw_Word; + SelLines : Sw_Word; + Lines : Sw_Word; + NewSize : Longint; +begin + InsertBuffer := True; + Selecting := False; + SelLen := SelEnd - SelStart; + if (SelLen = 0) and (Length = 0) then + Exit; + DelLen := 0; + if AllowUndo then + if CurPtr = SelStart then + DelLen := SelLen + else + if SelLen > InsCount then + DelLen := SelLen - InsCount; + NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length; + if NewSize > BufLen + DelCount then + if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then + begin + EditorDialog (edOutOfMemory, nil); + InsertBuffer := False; + SelEnd := SelStart; + Exit; + end; + SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen); + if CurPtr = SelEnd then + begin + if AllowUndo then + begin + if DelLen > 0 then + Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen); + Dec (InsCount, SelLen - DelLen); + end; + CurPtr := SelStart; + Dec (CurPos.Y, SelLines); + end; + if Delta.Y > CurPos.Y then + begin + Dec (Delta.Y, SelLines); + if Delta.Y < CurPos.Y then + Delta.Y := CurPos.Y; + end; + if Length > 0 then + Move (P^[Offset], Buffer^[CurPtr], Length); + Lines := CountLines (Buffer^[CurPtr], Length); + Inc (CurPtr, Length); + Inc (CurPos.Y, Lines); + DrawLine := CurPos.Y; + DrawPtr := LineStart (CurPtr); + CurPos.X := CharPos (DrawPtr, CurPtr); + if not SelectText then + SelStart := CurPtr; + SelEnd := CurPtr; + if Length>Sellen then + begin + Inc (BufLen, Length - SelLen); + Dec (GapLen, Length - SelLen); + end + else + begin + Dec (BufLen, Sellen - Length); + Inc (GapLen, Sellen - Length); + end; + if AllowUndo then + begin + Inc (DelCount, DelLen); + Inc (InsCount, Length); + end; + Inc (Limit.Y, Lines - SelLines); + Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y)); + if not IsClipboard then + Modified := True; + SetBufSize (BufLen + DelCount); + if (SelLines = 0) and (Lines = 0) then + Update (ufLine) + else + Update (ufView); +end; { TEditor.InsertBuffer } + + +function TEditor.InsertFrom (Editor : PEditor) : Boolean; +begin + InsertFrom := InsertBuffer (Editor^.Buffer, + Editor^.BufPtr (Editor^.SelStart), + Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard); +end; { TEditor.InsertFrom } + + +procedure TEditor.Insert_Line (Select_Mode : Byte); +{ This procedure inserts a newline at the current cursor position } +{ if a ^N is pressed. Unlike cmNewLine, the cursor will return } +{ to its original position. If the cursor was at the end of a } +{ line, and its spaces were removed, the cursor returns to the } +{ end of the line instead. } +begin + NewLine (Select_Mode); + SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode); +end; { TEditor.Insert_Line } + + +function TEditor.InsertText (Text : Pointer; + Length : Sw_Word; + SelectText : Boolean) : Boolean; +begin + if assigned(Text) and not Search_Replace then + Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd); + InsertText := InsertBuffer (PEditBuffer (Text), + 0, Length, CanUndo, SelectText); +end; { TEditor.InsertText } + + +function TEditor.IsClipboard : Boolean; +begin + IsClipboard := Clipboard = @Self; +end; { TEditor.IsClipboard } + + +procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte); +{ This procedure jumps to a place marker if ^Q# is pressed. } +{ We don't go anywhere if Place_Marker[Element] is not zero. } +begin + if (not IsClipboard) and (Place_Marker[Element] <> 0) then + SetCurPtr (Place_Marker[Element], Select_Mode); +end; { TEditor.Jump_Place_Marker } + + +procedure TEditor.Jump_To_Line (Select_Mode : Byte); +{ This function brings up a dialog box that allows } +{ the user to select a line number to jump to. } +VAR + Code : Integer; { Used for Val conversion. } + Temp_Value : Longint; { Holds converted dialog value. } +begin + if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then + begin + { Convert the Line_Number string to an interger. } + { Put it into Temp_Value. If the number is not } + { in the range 1..9999 abort. If the number is } + { our current Y position, abort. Otherwise, } + { go to top of document, and jump to the line. } + { There are faster methods. This one's easy. } + { Note that CurPos.Y is always 1 less than what } + { the TIndicator line says. } + val (Line_Number, Temp_Value, Code); + if (Temp_Value < 1) or (Temp_Value > 9999999) then + Exit; + if Temp_Value = CurPos.Y + 1 then + Exit; + SetCurPtr (0, Select_Mode); + SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode); + end; +end; {TEditor.Jump_To_Line} + + +function TEditor.LineEnd (P : Sw_Word) : Sw_Word; +var + start, + i : Sw_word; + pc : pchar; +begin + if P0) do + begin + if pc^ in [#10,#13] then + begin + LineEnd:=pc-pchar(Buffer); + exit; + end; + inc(pc); + dec(i); + end; + start:=CurPtr; + end + else + start:=P; + i:=BufLen-Start; + pc:=pchar(Buffer)+GapLen+start; + while (i>0) do + begin + if pc^ in [#10,#13] then + begin + LineEnd:=pc-(pchar(Buffer)+Gaplen); + exit; + end; + inc(pc); + dec(i); + end; + LineEnd:=pc-(pchar(Buffer)+Gaplen); +end; { TEditor.LineEnd } + + +function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word; +VAR + Pos : Sw_Integer; + I : Sw_Word; +begin + I := P; + P := LineStart (P); + Pos := CharPos (P, I); + while Count <> 0 do + begin + I := P; + if Count < 0 then + begin + P := PrevLine (P); + Inc (Count); + end + else + begin + P := NextLine (P); + Dec (Count); + end; + end; + if P <> I then + P := CharPtr (P, Pos); + LineMove := P; +end; { TEditor.LineMove } + + +function TEditor.LineStart (P : Sw_Word) : Sw_Word; +var + i : Sw_word; + start,pc : pchar; + oc : char; +begin + if P>CurPtr then + begin + start:=pchar(Buffer)+GapLen; + pc:=start; + i:=P-CurPtr; + dec(pc); + while (i>0) do + begin + if pc^ in [#10,#13] then + break; + dec(pc); + dec(i); + end; + end + else + i:=0; + if i=0 then + begin + start:=pchar(Buffer); + i:=P; + pc:=start+p; + dec(pc); + while (i>0) do + begin + if pc^ in [#10,#13] then + break; + dec(pc); + dec(i); + end; + if i=0 then + begin + LineStart:=0; + exit; + end; + end; + oc:=pc^; + LineStart:=pc-start+1; +end; { TEditor.LineStart } + + +function TEditor.LineNr (P : Sw_Word) : Sw_Word; +var + pc,endp : pchar; + lines : sw_word; +begin + endp:=pchar(Buffer)+BufPtr(P); + pc:=pchar(Buffer); + lines:=0; + while (pc=endp) then + break; + end; + end; + inc(pc); + end; + LineNr:=Lines; +end; + + +procedure TEditor.Lock; +begin + Inc (LockCount); +end; { TEditor.Lock } + + +function TEditor.NewLine (Select_Mode : Byte) : Boolean; +VAR + I : Sw_Word; { Used to track spaces for AutoIndent. } + P : Sw_Word; { Position of Cursor when we arrive and after Newline. } +begin + P := LineStart (CurPtr); + I := P; + { The first thing we do is remove any End Of Line spaces. } + { Then we check to see how many spaces are on beginning } + { of a line. We need this check to add them after CR/LF } + { if AutoIndenting. Last of all we insert spaces required } + { for the AutoIndenting, if it was on. } + Remove_EOL_Spaces (Select_Mode); + while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do + Inc (I); + if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then + exit; + if AutoIndent then + InsertText (@Buffer^[P], I - P, False); + { Remember where the CurPtr is at this moment. } + { Remember the length of the buffer at the moment. } + { Go to the previous line and remove EOL spaces. } + { Once removed, re-set the cursor to where we were } + { minus any spaces that might have been removed. } + I := BufLen; + P := CurPtr; + SetCurPtr (LineMove (CurPtr, - 1), Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if I - BufLen <> 0 then + SetCurPtr (P - (I - BufLen), Select_Mode) + else + SetCurPtr (P, Select_Mode); + NewLine:=true; +end; { TEditor.NewLine } + + +function TEditor.NextChar (P : Sw_Word) : Sw_Word; +var + pc : pchar; +begin + if P<>BufLen then + begin + inc(P); + if P<>BufLen then + begin + pc:=pchar(Buffer); + if P>=CurPtr then + inc(pc,GapLen); + inc(pc,P-1); + if ord(pc^)+ord((pc+1)^)=23 then + inc(p); + end; + end; + NextChar:=P; +end; { TEditor.NextChar } + + +function TEditor.NextLine (P : Sw_Word) : Sw_Word; +begin + NextLine := NextChar (LineEnd (P)); +end; { TEditor.NextLine } + + +function TEditor.NextWord (P : Sw_Word) : Sw_Word; +begin + { skip word } + while (P < BufLen) and (BufChar (P) in WordChars) do + P := NextChar (P); + { skip spaces } + while (P < BufLen) and not (BufChar (P) in WordChars) do + P := NextChar (P); + NextWord := P; +end; { TEditor.NextWord } + + +function TEditor.PrevChar (P : Sw_Word) : Sw_Word; +var + pc : pchar; +begin + if p<>0 then + begin + dec(p); + if p<>0 then + begin + pc:=pchar(Buffer); + if P>=CurPtr then + inc(pc,GapLen); + inc(pc,P-1); + if ord(pc^)+ord((pc+1)^)=23 then + dec(p); + end; + end; + PrevChar:=P; +end; { TEditor.PrevChar } + + +function TEditor.PrevLine (P : Sw_Word) : Sw_Word; +begin + PrevLine := LineStart (PrevChar (P)); +end; { TEditor.PrevLine } + + +function TEditor.PrevWord (P : Sw_Word) : Sw_Word; +begin + { skip spaces } + while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do + P := PrevChar (P); + { skip word } + while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do + P := PrevChar (P); + PrevWord := P; +end; { TEditor.PrevWord } + + +procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean); +{ This procedure will do a reformat of the entire document, or just } +{ from the current line to the end of the document, if ^QU is pressed. } +{ It simply brings up the correct dialog box, and then calls the } +{ TEditor.Reformat_Paragraph procedure to do the actual reformatting. } +CONST + efCurrentLine = $0000; { Radio button #1 selection for dialog box. } + efWholeDocument = $0001; { Radio button #2 selection for dialog box. } +VAR + Reformat_Options : Word; { Holds the dialog options for reformatting. } +begin + { Check if Word_Wrap is toggled on. If NOT on, check if programmer } + { allows reformatting of document and if not show user dialog that } + { says reformatting is not permissable. } + if not Word_Wrap then + begin + if not Allow_Reformat then + begin + EditorDialog (edReformatNotAllowed, nil); + Exit; + end; + Word_Wrap := True; + Update (ufStats); + end; + { Default radio button option to 1st one. Bring up dialog box. } + Reformat_Options := efCurrentLine; + if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then + begin + { If the option to reformat the whole document was selected } + { we need to go back to start of document. Otherwise we stay } + { on the current line. Call Reformat_Paragraph until we get } + { to the end of the document to do the reformatting. } + if Reformat_Options and efWholeDocument <> 0 then + SetCurPtr (0, Select_Mode); + Unlock; + repeat + Lock; + if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then + Exit; + TrackCursor (False); + Unlock; + until CurPtr = BufLen; + end; +end; { TEditor.Reformat_Document } + + +function TEditor.Reformat_Paragraph (Select_Mode : Byte; + Center_Cursor : Boolean) : Boolean; +{ This procedure will do a reformat of the current paragraph if ^B pressed. } +{ The feature works regardless if wordrap is on or off. It also supports } +{ the AutoIndent feature. Reformat is not possible if the CurPos exceeds } +{ the Right_Margin. Right_Margin is where the EOL is considered to be. } +CONST + Space : array [1..2] of Char = #32#32; +VAR + C : Sw_Word; { Position of CurPtr when we come into procedure. } + E : Sw_Word; { End of a line. } + S : Sw_Word; { Start of a line. } +begin + Reformat_Paragraph := False; + { Check if Word_Wrap is toggled on. If NOT on, check if programmer } + { allows reformatting of paragraph and if not show user dialog that } + { says reformatting is not permissable. } + if not Word_Wrap then + begin + if not Allow_Reformat then + begin + EditorDialog (edReformatNotAllowed, nil); + Exit; + end; + Word_Wrap := True; + Update (ufStats); + end; + C := CurPtr; + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { Reformat possible only if current line is NOT blank! } + if E <> S then + begin + { Reformat is NOT possible if the first word } + { on the line is beyond the Right_Margin. } + S := LineStart (CurPtr); + if NextWord (S) - S >= Right_Margin - 1 then + begin + EditorDialog (edReformNotPossible, nil); + Exit; + end; + { First objective is to find the first blank line } + { after this paragraph so we know when to stop. } + { That could be the end of the document. } + Repeat + SetCurPtr (LineMove (CurPtr, 1), Select_Mode); + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + BlankLine := E; + until ((CurPtr = BufLen) or (E = S)); + SetCurPtr (C, Select_Mode); + repeat + { Set CurPtr to LineEnd and remove the EOL spaces. } + { Pull up the next line and remove its EOL space. } + { First make sure the next line is not BlankLine! } + { Insert spaces as required between the two lines. } + SetCurPtr (LineEnd (CurPtr), Select_Mode); + Remove_EOL_Spaces (Select_Mode); + if CurPtr <> Blankline - 2 then + DeleteRange (CurPtr, Nextword (CurPtr), True); + Remove_EOL_Spaces (Select_Mode); + case Buffer^[CurPtr-1] of + '!' : InsertText (@Space, 2, False); + '.' : InsertText (@Space, 2, False); + ':' : InsertText (@Space, 2, False); + '?' : InsertText (@Space, 2, False); + else + InsertText (@Space, 1, False); + end; + { Reset CurPtr to EOL. While line length is > Right_Margin } + { go Do_Word_Wrap. If wordrap failed, exit routine. } + SetCurPtr (LineEnd (CurPtr), Select_Mode); + while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do + if not Do_Word_Wrap (Select_Mode, Center_Cursor) then + Exit; + { If LineEnd - LineStart > Right_Margin then set CurPtr } + { to Right_Margin on current line. Otherwise we set the } + { CurPtr to LineEnd. This gyration sets up the conditions } + { to test for time of loop exit. } + if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then + SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode) + else + SetCurPtr (LineEnd (CurPtr), Select_Mode); + until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2)); + end; + { If not at the end of the document reset CurPtr to start of next line. } + { This should be a blank line between paragraphs. } + if CurPtr < BufLen then + SetCurPtr (LineMove (CurPtr, 1), Select_Mode); + Reformat_Paragraph := True; +end; { TEditor.Reformat_Paragraph } + + +procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte); +{ This procedure tests to see if there are consecutive spaces } +{ at the end of a line (EOL). If so, we delete all spaces } +{ after the last non-space character to the end of line. } +{ We then reset the CurPtr to where we ended up at. } +VAR + C : Sw_Word; { Current pointer when we come into procedure. } + E : Sw_Word; { End of line. } + P : Sw_Word; { Position of pointer at any given moment. } + S : Sw_Word; { Start of a line. } +begin + C := CurPtr; + E := LineEnd (CurPtr); + P := E; + S := LineStart (CurPtr); + { Start at the end of a line and move towards the start. } + { Find first non-space character in that direction. } + while (P > S) and (BufChar (PrevChar (P)) = #32) do + P := PrevChar (P); + { If we found any spaces then delete them. } + if P < E then + begin + SetSelect (P, E, True); + DeleteSelect; + Update_Place_Markers (0, E - P, P, E); + end; + { If C, our pointer when we came into this procedure, } + { is less than the CurPtr then reset CurPtr to C so } + { cursor is where we started. Otherwise, set it to } + { the new CurPtr, for we have deleted characters. } + if C < CurPtr then + SetCurPtr (C, Select_Mode) + else + SetCurPtr (CurPtr, Select_Mode); +end; { TEditor.Remove_EOL_Spaces } + + +procedure TEditor.Replace; +VAR + ReplaceRec : TReplaceDialogRec; +begin + with ReplaceRec do + begin + Find := FindStr; + Replace := ReplaceStr; + Options := Flags; + if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then + begin + FindStr := Find; + ReplaceStr := Replace; + Flags := Options or efDoReplace; + DoSearchReplace; + end; + end; +end; { TEditor.Replace } + + +procedure TEditor.Scroll_Down; +{ This procedure will scroll the screen up, and always keep } +{ the cursor on the CurPos.Y position, but not necessarily on } +{ the CurPos.X. If CurPos.Y scrolls off the screen, the cursor } +{ will stay in the upper left corner of the screen. This will } +{ simulate the same process in the IDE. The CurPos.X coordinate } +{ only messes up if we are on long lines and we then encounter } +{ a shorter or blank line beneath the current one as we scroll. } +{ In that case, it goes to the end of the new line. } +VAR + C : Sw_Word; { Position of CurPtr when we enter procedure. } + P : Sw_Word; { Position of CurPtr at any given time. } + W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). } +begin + { Remember current cursor position. Remember current CurPos.Y position. } + { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will } + { go to the bottom of the current screen. Reset the cursor to this new } + { position and then send FALSE to TrackCursor so we fool it into } + { incrementing Delta.Y by only +1. If we didn't do this it would try } + { to center the cursor on the screen by fiddling with Delta.Y. } + C := CurPtr; + W.X := CurPos.Y; + P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y); + SetCurPtr (P, 0); + TrackCursor (False); + { Now remember where the new CurPos.Y is. See if distance between new } + { CurPos.Y and old CurPos.Y are greater than the current screen size. } + { If they are, we need to move cursor position itself down by one. } + { Otherwise, send the cursor back to our original CurPtr. } + W.Y := CurPos.Y; + if W.Y - W.X > Size.Y - 1 then + SetCurPtr (LineMove (C, 1), 0) + else + SetCurPtr (C, 0); +end; { TEditor.Scroll_Down } + + +procedure TEditor.Scroll_Up; +{ This procedure will scroll the screen down, and always keep } +{ the cursor on the CurPos.Y position, but not necessarily on } +{ the CurPos.X. If CurPos.Y scrolls off the screen, the cursor } +{ will stay in the bottom left corner of the screen. This will } +{ simulate the same process in the IDE. The CurPos.X coordinate } +{ only messes up if we are on long lines and we then encounter } +{ a shorter or blank line beneath the current one as we scroll. } +{ In that case, it goes to the end of the new line. } +VAR + C : Sw_Word; { Position of CurPtr when we enter procedure. } + P : Sw_Word; { Position of CurPtr at any given time. } + W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). } +begin + { Remember current cursor position. Remember current CurPos.Y position. } + { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will } + { go to the top of the current screen. Reset the cursor to this new } + { position and then send FALSE to TrackCursor so we fool it into } + { decrementing Delta.Y by only -1. If we didn't do this it would try } + { to center the cursor on the screen by fiddling with Delta.Y. } + C := CurPtr; + W.Y := CurPos.Y; + P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1)); + SetCurPtr (P, 0); + TrackCursor (False); + { Now remember where the new CurPos.Y is. See if distance between new } + { CurPos.Y and old CurPos.Y are greater than the current screen size. } + { If they are, we need to move the cursor position itself up by one. } + { Otherwise, send the cursor back to our original CurPtr. } + W.X := CurPos.Y; + if W.Y - W.X > Size.Y - 1 then + SetCurPtr (LineMove (C, -1), 0) + else + SetCurPtr (C, 0); +end; { TEditor.Scroll_Up } + + +procedure TEditor.ScrollTo (X, Y : Sw_Integer); +begin + X := Max (0, Min (X, Limit.X - Size.X)); + Y := Max (0, Min (Y, Limit.Y - Size.Y)); + if (X <> Delta.X) or (Y <> Delta.Y) then + begin + Delta.X := X; + Delta.Y := Y; + Update (ufView); + end; +end; { TEditor.ScrollTo } + + +function TEditor.Search (const FindStr : String; Opts : Word) : Boolean; +VAR + I,Pos : Sw_Word; +begin + Search := False; + Pos := CurPtr; + repeat + if Opts and efCaseSensitive <> 0 then + I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr) + else + I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr); + if (I <> sfSearchFailed) then + begin + Inc (I, Pos); + if (Opts and efWholeWordsOnly = 0) or + not (((I <> 0) and (BufChar (I - 1) in WordChars)) or + ((I + Length (FindStr) <> BufLen) and + (BufChar (I + Length (FindStr)) in WordChars))) then + begin + Lock; + SetSelect (I, I + Length (FindStr), False); + TrackCursor (not CursorVisible); + Unlock; + Search := True; + Exit; + end + else + Pos := I + 1; + end; + until I = sfSearchFailed; +end; { TEditor.Search } + + +procedure TEditor.Select_Word; +{ This procedure will select the a word to put into the clipboard. } +{ I've added it just to maintain compatibility with the IDE editor. } +{ Note that selection starts at the current cursor position and ends } +{ when a space or the end of line is encountered. } +VAR + E : Sw_Word; { End of the current line. } + Select_Mode : Byte; { Allows us to turn select mode on inside procedure. } +begin + E := LineEnd (CurPtr); + { If the cursor is on a space or at the end of a line, abort. } + { Stupid action on users part for you can't select blanks! } + if (BufChar (CurPtr) = #32) or (CurPtr = E) then + Exit; + { Turn on select mode and tell editor to start selecting text. } + { As long as we have a character > a space (this is done to } + { exclude CR/LF pairs at end of a line) and we are NOT at the } + { end of a line, set the CurPtr to the next character. } + { Once we find a space or CR/LF, selection is done and we } + { automatically put the selected word into the Clipboard. } + Select_Mode := smExtend; + StartSelect; + while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do + SetCurPtr (NextChar (CurPtr), Select_Mode); + SetCurPtr (NextChar (CurPtr), Select_Mode); + ClipCopy; +end; {TEditor.Select_Word } + + +procedure TEditor.SetBufLen (Length : Sw_Word); +begin + BufLen := Length; + GapLen := BufSize - Length; + SelStart := 0; + SelEnd := 0; + CurPtr := 0; + CurPos.X:=0; + CurPos.Y:=0; + Delta.X:=0; + Delta.Y:=0; + GetLimits(Buffer^[GapLen], BufLen,Limit); + inc(Limit.X); + inc(Limit.Y); + DrawLine := 0; + DrawPtr := 0; + DelCount := 0; + InsCount := 0; + Modified := False; + Update (ufView); +end; { TEditor.SetBufLen } + + +function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean; +begin + SetBufSize := NewSize <= BufSize; +end; { TEditor.SetBufSize } + + +procedure TEditor.SetCmdState (Command : Word; Enable : Boolean); +VAR + S : TCommandSet; +begin + S := [Command]; + if Enable and (State and sfActive <> 0) then + EnableCommands (S) + else + DisableCommands (S); +end; { TEditor.SetCmdState } + + +procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte); +VAR + Anchor : Sw_Word; +begin + if SelectMode and smExtend = 0 then + Anchor := P + else + if CurPtr = SelStart then + Anchor := SelEnd + else + Anchor := SelStart; + if P < Anchor then + begin + if SelectMode and smDouble <> 0 then + begin + P := PrevLine (NextLine (P)); + Anchor := NextLine (PrevLine (Anchor)); + end; + SetSelect (P, Anchor, True); + end + else + begin + if SelectMode and smDouble <> 0 then + begin + P := NextLine (P); + Anchor := PrevLine (NextLine (Anchor)); + end; + SetSelect (Anchor, P, False); + end; +end; { TEditor.SetCurPtr } + + +procedure TEditor.Set_Place_Marker (Element : Byte); +{ This procedure sets a place marker for the CurPtr if ^K# is pressed. } +begin + if not IsClipboard then + Place_Marker[Element] := CurPtr; +end; { TEditor.Set_Place_Marker } + + +procedure TEditor.Set_Right_Margin; +{ This procedure will bring up a dialog box } +{ that allows the user to set Right_Margin. } +{ Values must be < MaxLineLength and > 9. } +VAR + Code : Integer; { Used for Val conversion. } + Margin_Data : TRightMarginRec; { Holds dialog results. } + Temp_Value : Sw_Integer; { Holds converted dialog value. } +begin + with Margin_Data do + begin + Str (Right_Margin, Margin_Position); + if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then + begin + val (Margin_Position, Temp_Value, Code); + if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then + Right_Margin := Temp_Value; + end; + end; +end; { TEditor.Set_Right_Margin } + + +procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean); +VAR + UFlags : Byte; + P : Sw_Word; + L : Sw_Word; +begin + if CurStart then + P := NewStart + else + P := NewEnd; + UFlags := ufUpdate; + if (NewStart <> SelStart) or (NewEnd <> SelEnd) then + if (NewStart <> NewEnd) or (SelStart <> SelEnd) then + UFlags := ufView; + if P <> CurPtr then + begin + if P > CurPtr then + begin + L := P - CurPtr; + Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L); + Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L)); + CurPtr := P; + end + else + begin + L := CurPtr - P; + CurPtr := P; + Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L)); + Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L); + end; + DrawLine := CurPos.Y; + DrawPtr := LineStart (P); + CurPos.X := CharPos (DrawPtr, P); + DelCount := 0; + InsCount := 0; + SetBufSize (BufLen); + end; + SelStart := NewStart; + SelEnd := NewEnd; + Update (UFlags); +end; { TEditor.Select } + + +procedure TEditor.SetState (AState : Word; Enable : Boolean); +begin + Inherited SetState (AState, Enable); + case AState of + sfActive: begin + if assigned(HScrollBar) then + HScrollBar^.SetState (sfVisible, Enable); + if assigned(VScrollBar) then + VScrollBar^.SetState (sfVisible, Enable); + if assigned(Indicator) then + Indicator^.SetState (sfVisible, Enable); + UpdateCommands; + end; + sfExposed: if Enable then Unlock; + end; +end; { TEditor.SetState } + + +procedure TEditor.Set_Tabs; +{ This procedure will bring up a dialog box } +{ that allows the user to set tab stops. } +VAR + Index : Sw_Integer; { Index into string array. } + Tab_Data : TTabStopRec; { Holds dialog results. } +begin + with Tab_Data do + begin + { Assign current Tab_Settings to Tab_String. } + { Bring up the tab dialog so user can set tabs. } + Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length); + if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then + begin + { If Tab_String comes back as empty then set Tab_Settings to nil. } + { Otherwise, find the last character in Tab_String that is not } + { a space and copy Tab_String into Tab_Settings up to that spot. } + if Length (Tab_String) = 0 then + begin + FillChar (Tab_Settings, SizeOf (Tab_Settings), #0); + Tab_Settings[0] := #0; + Exit; + end + else + begin + Index := Length (Tab_String); + while Tab_String[Index] <= #32 do + Dec (Index); + Tab_Settings := Copy (Tab_String, 1, Index); + end; + end; + end; +end; { TEditor.Set_Tabs } + + +procedure TEditor.StartSelect; +begin + HideSelect; + Selecting := True; +end; { TEditor.StartSelect } + + +procedure TEditor.Store (var S : Objects.TStream); +begin + Inherited Store (S); + PutPeerViewPtr (S, HScrollBar); + PutPeerViewPtr (S, VScrollBar); + PutPeerViewPtr (S, Indicator); + S.Write (BufSize, SizeOf (Sw_Word)); + S.Write (Canundo, SizeOf (Boolean)); + S.Write (AutoIndent, SizeOf (AutoIndent)); + S.Write (Line_Number, SizeOf (Line_Number)); + S.Write (Place_Marker, SizeOf (Place_Marker)); + S.Write (Right_Margin, SizeOf (Right_Margin)); + S.Write (Tab_Settings, SizeOf (Tab_Settings)); + S.Write (Word_Wrap, SizeOf (Word_Wrap)); +end; { Editor.Store } + + +procedure TEditor.Tab_Key (Select_Mode : Byte); +{ This function determines if we are in overstrike or insert mode, } +{ and then moves the cursor if overstrike, or adds spaces if insert. } +VAR + E : Sw_Word; { End of current line. } + Index : Sw_Integer; { Loop counter. } + Position : Sw_Integer; { CurPos.X position. } + S : Sw_Word; { Start of current line. } + Spaces : array [1..80] of Char; { Array to hold spaces for insertion. } +begin + E := LineEnd (CurPtr); + S := LineStart (CurPtr); + { Find the current horizontal cursor position. } + { Now loop through the Tab_Settings string and } + { find the next available tab stop. } + Position := CurPos.X + 1; + repeat + Inc (Position); + until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0])); + E := CurPos.X; + Index := 1; + { Now we enter a loop to go to the next tab position. } + { If we are in overwrite mode, we just move the cursor } + { through the text to the next tab stop. If we are in } + { insert mode, we add spaces to the Spaces array for } + { the number of times we loop. } + while Index < Position - E do + begin + if Overwrite then + begin + if (Position > LineEnd (CurPtr) - LineStart (CurPtr)) + or (Position > Ord (Tab_Settings[0])) then + begin + SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode); + Exit; + end + else + if CurPtr < BufLen then + SetCurPtr (NextChar (CurPtr), Select_Mode); + end + else + begin + if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then + begin + SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode); + Exit; + end + else + Spaces[Index] := #32; + end; + Inc (Index); + end; + { If we are insert mode, we insert spaces to the next tab stop. } + { When we're all done, the cursor will be sitting on the new tab stop. } + if not OverWrite then + InsertText (@Spaces, Index - 1, False); +end; { TEditor.Tab_Key } + + +procedure TEditor.ToggleInsMode; +begin + Overwrite := not Overwrite; + SetState (sfCursorIns, not GetState (sfCursorIns)); +end; { TEditor.ToggleInsMode } + + +procedure TEditor.TrackCursor (Center : Boolean); +begin + if Center then + ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2) + else + ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)), + Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y))); +end; { TEditor.TrackCursor } + + +procedure TEditor.Undo; +VAR + Length : Sw_Word; +begin + if (DelCount <> 0) or (InsCount <> 0) then + begin + Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount); + SelStart := CurPtr - InsCount; + SelEnd := CurPtr; + Length := DelCount; + DelCount := 0; + InsCount := 0; + InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True); + end; +end; { TEditor.Undo } + + +procedure TEditor.Unlock; +begin + if LockCount > 0 then + begin + Dec (LockCount); + if LockCount = 0 then + DoUpdate; + end; +end; { TEditor.Unlock } + + +procedure TEditor.Update (AFlags : Byte); +begin + UpdateFlags := UpdateFlags or AFlags; + if LockCount = 0 then + DoUpdate; +end; { TEditor.Update } + + +procedure TEditor.UpdateCommands; +begin + SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0)); + if not IsClipboard then + begin + SetCmdState (cmCut, HasSelection); + SetCmdState (cmCopy, HasSelection); + SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection)); + end; + SetCmdState (cmClear, HasSelection); + SetCmdState (cmFind, True); + SetCmdState (cmReplace, True); + SetCmdState (cmSearchAgain, True); +end; { TEditor.UpdateCommands } + + +procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word; + StartPtr,EndPtr : Sw_Word); +{ This procedure updates the position of the place markers } +{ as the user inserts and deletes text in the document. } +VAR + Element : Byte; { Place_Marker array element to traverse array with. } +begin + for Element := 1 to 10 do + begin + if AddCount > 0 then + begin + if (Place_Marker[Element] >= Curptr) + and (Place_Marker[Element] <> 0) then + Place_Marker[Element] := Place_Marker[Element] + AddCount; + end + else + begin + if Place_Marker[Element] >= StartPtr then + begin + if (Place_Marker[Element] >= StartPtr) and + (Place_Marker[Element] < EndPtr) then + Place_marker[Element] := 0 + else + begin + if integer (Place_Marker[Element]) - integer (KillCount) > 0 then + Place_Marker[Element] := Place_Marker[Element] - KillCount + else + Place_Marker[Element] := 0; + end; + end; + end; + end; + if AddCount > 0 then + BlankLine := BlankLine + AddCount + else + begin + if integer (BlankLine) - Integer (KillCount) > 0 then + BlankLine := BlankLine - KillCount + else + BlankLine := 0; + end; +end; { TEditor.Update_Place_Markers } + + +function TEditor.Valid (Command : Word) : Boolean; +begin + Valid := IsValid; +end; { TEditor.Valid } + + +{**************************************************************************** + TMEMO +****************************************************************************} + +constructor TMemo.Load (var S : Objects.TStream); +VAR + Length : Sw_Word; +begin + Inherited Load (S); + S.Read (Length, SizeOf (Sw_Word)); + if IsValid then + begin + S.Read (Buffer^[BufSize - Length], Length); + SetBufLen (Length); + end + else + S.Seek (S.GetPos + Length); +end; { TMemo.Load } + + +function TMemo.DataSize : Sw_Word; +begin + DataSize := BufSize + SizeOf (Sw_Word); +end; { TMemo.DataSize } + + +procedure TMemo.GetData (var Rec); +VAR + Data : TMemoData absolute Rec; +begin + Data.Length := BufLen; + Move (Buffer^, Data.Buffer, CurPtr); + Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr); + FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0); +end; { TMemo.GetData } + + +function TMemo.GetPalette : PPalette; +CONST + P : String[Length (CMemo)] = CMemo; +begin + GetPalette := @P; +end; { TMemo.GetPalette } + + +procedure TMemo.HandleEvent (var Event : Drivers.TEvent); +begin + if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then + Inherited HandleEvent (Event); +end; { TMemo.HandleEvent } + + +procedure TMemo.SetData (var Rec); +VAR + Data : TMemoData absolute Rec; +begin + Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length); + SetBufLen (Data.Length); +end; { TMemo.SetData } + + +procedure TMemo.Store (var S : Objects.TStream); +begin + Inherited Store (S); + S.Write (BufLen, SizeOf (Sw_Word)); + S.Write (Buffer^, CurPtr); + S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr); +end; { TMemo.Store } + + +{**************************************************************************** + TFILEEDITOR +****************************************************************************} + + +constructor TFileEditor.Init (var Bounds : TRect; + AHScrollBar, AVScrollBar : PScrollBar; + AIndicator : PIndicator; + AFileName : FNameStr); +begin + Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0); + if AFileName <> '' then + begin + FileName := FExpand (AFileName); + if IsValid then + IsValid := LoadFile; + end; +end; { TFileEditor.Init } + + +constructor TFileEditor.Load (var S : Objects.TStream); +VAR + SStart,SEnd,Curs : Sw_Word; +begin + Inherited Load (S); + BufSize := 0; + S.Read (FileName[0], SizeOf (Char)); + S.Read (Filename[1], Length (FileName)); + if IsValid then + IsValid := LoadFile; + S.Read (SStart, SizeOf (Sw_Word)); + S.Read (SEnd, SizeOf (Sw_Word)); + S.Read (Curs, SizeOf (Sw_Word)); + if IsValid and (SEnd <= BufLen) then + begin + SetSelect (SStart, SEnd, Curs = SStart); + TrackCursor (True); + end; +end; { TFileEditor.Load } + + +procedure TFileEditor.DoneBuffer; +begin + if assigned(Buffer) then + DisposeBuffer (Buffer); +end; { TFileEditor.DoneBuffer } + + +procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent); +begin + Inherited HandleEvent (Event); + case Event.What of + Drivers.evCommand: + case Event.Command of + cmSave : Save; + cmSaveAs : SaveAs; + cmSaveDone : if Save then + Message (Owner, Drivers.evCommand, cmClose, nil); + else + Exit; + end; + else + Exit; + end; + ClearEvent (Event); +end; { TFileEditor.HandleEvent } + + +procedure TFileEditor.InitBuffer; +begin + NewBuffer(Pointer(Buffer), MinBufLength); +end; { TFileEditor.InitBuffer } + + +function TFileEditor.LoadFile: Boolean; +VAR + Length : Sw_Word; + FSize : Longint; + FRead : Sw_Integer; + F : File; +begin + LoadFile := False; + Length := 0; + Assign(F, FileName); + Reset(F, 1); + if IOResult <> 0 then + EditorDialog(edReadError, @FileName) + else + begin + FSize := FileSize(F); + if (FSize > MaxBufLength) or not SetBufSize(FSize) then + EditorDialog(edOutOfMemory, nil) + else + begin + BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead); + if (IOResult <> 0) or (FRead<>FSize) then + EditorDialog(edReadError, @FileName) + else + begin + LoadFile := True; + Length := FRead; + end; + end; + Close(F); + end; + SetBufLen(Length); +end; { TFileEditor.LoadFile } + + +function TFileEditor.Save : Boolean; +begin + if FileName = '' then + Save := SaveAs + else + Save := SaveFile; +end; { TFileEditor.Save } + + +function TFileEditor.SaveAs : Boolean; +begin + SaveAs := False; + if EditorDialog (edSaveAs, @FileName) <> cmCancel then + begin + FileName := FExpand (FileName); + Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil); + SaveAs := SaveFile; + if IsClipboard then + FileName := ''; + end; +end; { TFileEditor.SaveAs } + + +function TFileEditor.SaveFile : Boolean; +VAR + F : File; + BackupName : Objects.FNameStr; + D : DOS.DirStr; + N : DOS.NameStr; + E : DOS.ExtStr; +begin + SaveFile := False; + if Flags and efBackupFiles <> 0 then + begin + FSplit (FileName, D, N, E); + BackupName := D + N + '.bak'; + Assign (F, BackupName); + Erase (F); + Assign (F, FileName); + Rename (F, BackupName); + InOutRes := 0; + end; + Assign (F, FileName); + Rewrite (F, 1); + if IOResult <> 0 then + EditorDialog (edCreateError, @FileName) + else + begin + BlockWrite (F, Buffer^, CurPtr); + BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr); + if IOResult <> 0 then + EditorDialog (edWriteError, @FileName) + else + begin + Modified := False; + Update (ufUpdate); + SaveFile := True; + end; + Close (F); + end; +end; { TFileEditor.SaveFile } + + +function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean; +VAR + N : Sw_Word; +begin + SetBufSize := False; + if NewSize = 0 then + NewSize := MinBufLength + else + if NewSize > (MaxBufLength-MinBufLength) then + NewSize := MaxBufLength + else + NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1))); + if NewSize <> BufSize then + begin + if NewSize > BufSize then + if not SetBufferSize(pointer(Buffer), NewSize) then + Exit; + N := BufLen - CurPtr + DelCount; + Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N); + if NewSize < BufSize then + SetBufferSize(pointer(Buffer), NewSize); + BufSize := NewSize; + GapLen := BufSize - BufLen; + end; + SetBufSize := True; +end; { TFileEditor.SetBufSize } + + +procedure TFileEditor.Store (var S : Objects.TStream); +begin + Inherited Store (S); + S.Write (FileName, Length (FileName) + 1); + S.Write (SelStart, SizeOf (Sw_Word) * 3); +end; { TFileEditor.Store } + + +procedure TFileEditor.UpdateCommands; +begin + Inherited UpdateCommands; + SetCmdState (cmSave, True); + SetCmdState (cmSaveAs, True); + SetCmdState (cmSaveDone, True); +end; { TFileEditor.UpdateCommands } + + +function TFileEditor.Valid (Command : Word) : Boolean; +VAR + D : Integer; +begin + if Command = cmValid then + Valid := IsValid + else + begin + Valid := True; + if Modified then + begin + if FileName = '' then + D := edSaveUntitled + else + D := edSaveModify; + case EditorDialog (D, @FileName) of + cmYes : Valid := Save; + cmNo : Modified := False; + cmCancel : Valid := False; + end; + end; + end; +end; { TFileEditor.Valid } + + +{**************************************************************************** + TEDITWINDOW +****************************************************************************} + +constructor TEditWindow.Init (var Bounds : TRect; + FileName : Objects.FNameStr; + ANumber : Integer); +var + HScrollBar : PScrollBar; + VScrollBar : PScrollBar; + Indicator : PIndicator; + R : TRect; +begin + Inherited Init (Bounds, '', ANumber); + Options := Options or ofTileable; + + R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y); + HScrollBar := New (PScrollBar, Init (R)); + HScrollBar^.Hide; + Insert (HScrollBar); + + R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1); + VScrollBar := New (PScrollBar, Init (R)); + VScrollBar^.Hide; + Insert (VScrollBar); + + R.Assign (2, Size.Y - 1, 16, Size.Y); + Indicator := New (PIndicator, Init (R)); + Indicator^.Hide; + Insert (Indicator); + + GetExtent (R); + R.Grow (-1, -1); + Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName)); + Insert (Editor); +end; { TEditWindow.Init } + + +constructor TEditWindow.Load (var S : Objects.TStream); +begin + Inherited Load (S); + GetSubViewPtr (S, Editor); +end; { TEditWindow.Load } + + +procedure TEditWindow.Close; +begin + if Editor^.IsClipboard then + Hide + else + Inherited Close; +end; { TEditWindow.Close } + + +function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr; +begin + if Editor^.IsClipboard then + GetTitle := strings^.get(sClipboard) + else + if Editor^.FileName = '' then + GetTitle := strings^.get(sUntitled) + else + GetTitle := Editor^.FileName; +end; { TEditWindow.GetTile } + + +procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent); +begin + Inherited HandleEvent (Event); + if (Event.What = Drivers.evBroadcast) then + { and (Event.Command = cmUpdateTitle) then } + { Changed if statement above so I could test for cmBlugeonStats. } + { Stats would not show up when loading a file until a key was pressed. } + case Event.Command of + cmUpdateTitle : + begin + Frame^.DrawView; + ClearEvent (Event); + end; + cmBludgeonStats : + begin + Editor^.Update (ufStats); + ClearEvent (Event); + end; + end; +end; { TEditWindow.HandleEvent } + + +procedure TEditWindow.SizeLimits(var Min, Max: TPoint); +begin + inherited SizeLimits(Min, Max); + Min.X := 23; +end; + + +procedure TEditWindow.Store (var S : Objects.TStream); +begin + Inherited Store (S); + PutSubViewPtr (S, Editor); +end; { TEditWindow.Store } + + +procedure RegisterEditors; +begin + RegisterType (REditor); + RegisterType (RMemo); + RegisterType (RFileEditor); + RegisterType (RIndicator); + RegisterType (REditWindow); +end; { RegisterEditors } + + +end. { Unit NewEdit } diff --git a/fvision/str.inc b/fvision/str.inc new file mode 100644 index 0000000000..6bf78f42eb --- /dev/null +++ b/fvision/str.inc @@ -0,0 +1,189 @@ +{ Strings } +sButtonDefault = 1; { Button default } +sButtonDisabled = 2; { Button disabled } +sButtonNormal = 3; { Button normal } +sButtonSelected = 4; { Button selected } +sButtonShadow = 5; { Button shadow } +sButtonShortcut = 6; { Button shortcut } +sChangeDirectory = 7; { Change Directory } +sClipboard = 8; { Clipboard } +sClusterNormal = 9; { Cluster normal } +sClusterSelected = 10; { Cluster selected } +sClusterShortcut = 11; { Cluster shortcut } +sColor = 12; { Color } +sColors = 13; { Colors } +sConfirm = 14; { Confirm } +sDeleteFile = 15; { Delete file?#13#10#13#3%s } +sDirectory = 16; { Directory } +sDisabled = 17; { Disabled } +sDrives = 18; { Drives } +sError = 19; { Error } +sFileAlreadyOpen = 20; { #3%s#13#10#13#3is already open in window %d. } +sFileCreateError = 21; { Error creating file %s } +sFileReadError = 22; { Error reading file %s } +sFileUntitled = 23; { Save untitled file? } +sFileWriteError = 24; { Error writing to file %s } +sFind = 25; { Find } +sFrameActive = 26; { Frame active } +sFrameBackground = 27; { Frame/background } +sFrameIcons = 28; { Frame icons } +sFramePassive = 29; { Frame passive } +sHighlight = 30; { Highlight } +sHistoryBarIcons = 31; { History bar icons } +sHistoryBarPage = 32; { History bar page } +sHistoryButton = 33; { History button } +sHistorySides = 34; { History sides } +sInformation = 35; { Information } +sInformationPane = 36; { Information pane } +sInputArrow = 37; { Input arrow } +sInputNormal = 38; { Input normal } +sInputSelected = 39; { Input selected } +sInvalidCharacter = 40; { Invalid character in input } +sInvalidDirectory = 41; { Invalid directory. } +sInvalidDriveOrDir = 42; { Invalid drive or directory. } +sInvalidFileName = 43; { Invalid file name. } +sInvalidPicture = 44; { Input does not conform to picture: %s } +sInvalidValue = 45; { Value not in the range %d to %d } +sInverse = 46; { Inverse } +sJumpTo = 47; { Jump To } +sLabelNormal = 48; { Label normal } +sLabelSelected = 49; { Label selected } +sLabelShortcut = 50; { Label shortcut } +sListDivider = 51; { List divider } +sListFocused = 52; { List focused } +sListNormal = 53; { List normal } +sListSelected = 54; { List selected } +sModified = 55; { #3%s#13#10#13#3has been modified. Save? } +sNoName = 56; { NONAME } +sNormal = 57; { Normal } +sNormalText = 58; { Normal text } +sNotInList = 59; { Input not in valid-list } +sOpen = 60; { Open } +sOutOfMemory = 61; { Not enough memory for this operation. } +sOutOfUnNamedWindows = 62; { Out of unnamed window numbers. Save or discard some unnamed files and try again. } +sPasteNotPossible = 63; { Wordwrap on: Paste not possible in current margins when at end of line. } +sReformatDocument = 64; { Reformat Document } +sReformatNotPossible = 65; { Paragraph reformat not possible while trying to wrap current line with current margins. } +sReformattingTheDocument = 66; { Reformatting the document: } +sReplace = 67; { Replace } +sReplaceFile = 68; { Replace file?#13#10#13#3%s } +sReplaceNotPossible = 69; { Wordwrap on: Replace not possible in current margins when at end of line. } +sReplaceThisOccurence = 70; { Replace this occurence? } +sRightMargin = 71; { Right Margin } +sSaveAs = 72; { Save As } +sScrollbarIcons = 73; { Scroll bar icons } +sScrollbarPage = 74; { Scroll bar page } +sSearchStringNotFound = 75; { Search string not found. } +sSelectFormatStart = 76; { Select Format Start } +sSelectWhereToBegin = 77; { Please select where to begin. } +sSelected = 78; { Selected } +sSelectedDisabled = 79; { Selected disabled } +sSetting = 80; { Setting: } +sShortcut = 81; { Shortcut } +sShortcutSelected = 82; { ShortcutSelected } +sStaticText = 83; { Static text } +sTabSettings = 84; { Tab Settings } +sText = 85; { Text } +sTooManyFiles = 86; { Too many files. } +sTypeExitOnReturn = 87; { Type EXIT to return... } +sUnderline = 88; { Underline } +sUnknownDialog = 89; { Unknown dialog requested! } +sUntitled = 90; { Untitled } +sWarning = 91; { Warning } +sWindowList = 92; { Window List } +sWordWrapNotPossible = 93; { Wordwrap on: Wordwrap not possible in current margins with continuous line. } +sWordWrapOff = 94; { You must turn on wordwrap before you can reformat. } +smApr = 95; { Apr } +smAug = 96; { Aug } +smDec = 97; { Dec } +smFeb = 98; { Feb } +smJan = 99; { Jan } +smJul = 100; { Jul } +smJun = 101; { Jun } +smMar = 102; { Mar } +smMay = 103; { May } +smNov = 104; { Nov } +smOct = 105; { Oct } +smSep = 106; { Sep } +{ Labels } +slAbout = 107; { ~A~bout } +slAltF1 = 108; { Alt+F1 } +slAltF3Close = 109; { ~Alt+F3~ Close } +slAltXExit = 110; { ~Alt-X~ Exit } +slBackground = 111; { ~B~ackground } +slCancel = 112; { Cancel } +slCascade = 113; { C~a~scade } +slCaseSensitive = 114; { ~C~ase sensitive } +slChDir = 115; { ~C~hdir } +slChangeDir = 116; { ~C~hange dir... } +slClear = 117; { C~l~ear } +slClose = 118; { ~C~lose } +slCloseAll = 119; { Cl~o~se all } +slColor = 120; { ~C~olor } +slContents = 121; { ~C~ontents } +slCopy = 122; { ~C~opy } +slCtrlF1 = 123; { Ctrl+F1 } +slCurrentLine = 124; { ~C~urrent line } +slCut = 125; { Cu~t~ } +slDOSShell = 126; { ~D~OS shell } +slDelete = 127; { ~D~elete } +slDirectoryName = 128; { Directory ~n~ame } +slDirectoryTree = 129; { Directory ~t~ree } +slEdit = 130; { ~E~dit } +slEntireDocument = 131; { ~E~ntire document } +slExit = 132; { E~x~it } +slF10Menu = 133; { ~F10~ Menu } +slF1Help = 134; { ~F1~ Help } +slF3Open = 135; { ~F3~ Open } +slFile = 136; { ~F~ile } +slFiles = 137; { ~F~iles } +slForeground = 138; { ~F~oreground } +slGroup = 139; { ~G~roup } +slHelp = 140; { ~H~elp } +slIndex = 141; { ~I~ndex } +slItem = 142; { ~I~tem } +slLineNumber = 143; { ~L~ine number } +slName = 144; { ~N~ame } +slNew = 145; { ~N~ew } +slNewText = 146; { ~N~ew text } +slNext = 147; { ~N~ext } +slNo = 148; { ~N~o } +slOk = 149; { O~k~ } +slOpen = 150; { ~O~pen } +slOpenDots = 151; { ~O~pen... } +slPaste = 152; { ~P~aste } +slPrevious = 153; { ~P~revious } +slPreviousTopic = 154; { ~P~revious topic } +slPromptOnReplace = 155; { ~P~rompt on replace } +slReformatDocument = 156; { ~R~eformat document } +slReplace = 157; { ~R~eplace } +slReplaceAll = 158; { ~R~eplace all } +slRevert = 159; { ~R~evert } +slSave = 160; { ~S~ave } +slSaveAll = 161; { Save a~l~l } +slSaveAs = 162; { S~a~ve as... } +slSaveFileAs = 163; { ~S~ave file as } +slShiftF1 = 164; { Shift+F1 } +slSizeMove = 165; { ~S~ize/Move } +slTextToFind = 166; { ~T~ext to find } +slTile = 167; { ~T~ile } +slTopicSearch = 168; { ~T~opic search } +slUndo = 169; { ~U~ndo } +slUsingHelp = 170; { ~U~sing help } +slWholeWordsOnly = 171; { ~W~hole words only } +slWindow = 172; { ~W~indow } +slWindows = 173; { ~W~indows } +slYes = 174; { ~Y~es } +slZoom = 175; { ~Z~oom } +slAltF3 = 176; { Alt+F3 } +slAltX = 177; { Alt+X } +slF2 = 178; { F2 } +slF3 = 179; { F3 } +slF5 = 180; { F5 } +slF6 = 181; { F6 } +slCtrlDel = 182; { Ctrl+Del } +slCtrlF5 = 183; { Ctrl+F5 } +slCtrlIns = 184; { Ctrl+Ins } +slShiftDel = 185; { Shift+Del } +slShiftF6 = 186; { Shift+F6 } +slShiftIns = 187; { Shift+Ins } diff --git a/fvision/strtxt.inc b/fvision/strtxt.inc new file mode 100644 index 0000000000..fc854b7663 --- /dev/null +++ b/fvision/strtxt.inc @@ -0,0 +1,194 @@ +procedure InitResStrings; +begin + Strings^.Put(sButtonDefault,'Button default'); + Strings^.Put(sButtonDisabled,'Button disabled'); + Strings^.Put(sButtonNormal,'Button normal'); + Strings^.Put(sButtonSelected,'Button selected'); + Strings^.Put(sButtonShadow,'Button shadow'); + Strings^.Put(sButtonShortcut,'Button shortcut'); + Strings^.Put(sChangeDirectory,'Change Directory'); + Strings^.Put(sClipboard,'Clipboard'); + Strings^.Put(sClusterNormal,'Cluster normal'); + Strings^.Put(sClusterSelected,'Cluster selected'); + Strings^.Put(sClusterShortcut,'Cluster shortcut'); + Strings^.Put(sColor,'Color'); + Strings^.Put(sColors,'Colors'); + Strings^.Put(sConfirm,'Confirm'); + Strings^.Put(sDeleteFile,'Delete file?'#13#10#13#3'%s'); + Strings^.Put(sDirectory,'Directory'); + Strings^.Put(sDisabled,'Disabled'); + Strings^.Put(sDrives,'Drives'); + Strings^.Put(sError,'Error'); + Strings^.Put(sFileAlreadyOpen,''#3'%s'#13#10#13#3'is already open in window %d.'); + Strings^.Put(sFileCreateError,'Error creating file %s'); + Strings^.Put(sFileReadError,'Error reading file %s'); + Strings^.Put(sFileUntitled,'Save untitled file?'); + Strings^.Put(sFileWriteError,'Error writing to file %s'); + Strings^.Put(sFind,'Find'); + Strings^.Put(sFrameActive,'Frame active'); + Strings^.Put(sFrameBackground,'Frame/background'); + Strings^.Put(sFrameIcons,'Frame icons'); + Strings^.Put(sFramePassive,'Frame passive'); + Strings^.Put(sHighlight,'Highlight'); + Strings^.Put(sHistoryBarIcons,'History bar icons'); + Strings^.Put(sHistoryBarPage,'History bar page'); + Strings^.Put(sHistoryButton,'History button'); + Strings^.Put(sHistorySides,'History sides'); + Strings^.Put(sInformation,'Information'); + Strings^.Put(sInformationPane,'Information pane'); + Strings^.Put(sInputArrow,'Input arrow'); + Strings^.Put(sInputNormal,'Input normal'); + Strings^.Put(sInputSelected,'Input selected'); + Strings^.Put(sInvalidCharacter,'Invalid character in input'); + Strings^.Put(sInvalidDirectory,'Invalid directory.'); + Strings^.Put(sInvalidDriveOrDir,'Invalid drive or directory.'); + Strings^.Put(sInvalidFileName,'Invalid file name.'); + Strings^.Put(sInvalidPicture,'Input does not conform to picture: %s'); + Strings^.Put(sInvalidValue,'Value not in the range %d to %d'); + Strings^.Put(sInverse,'Inverse'); + Strings^.Put(sJumpTo,'Jump To'); + Strings^.Put(sLabelNormal,'Label normal'); + Strings^.Put(sLabelSelected,'Label selected'); + Strings^.Put(sLabelShortcut,'Label shortcut'); + Strings^.Put(sListDivider,'List divider'); + Strings^.Put(sListFocused,'List focused'); + Strings^.Put(sListNormal,'List normal'); + Strings^.Put(sListSelected,'List selected'); + Strings^.Put(sModified,''#3'%s'#13#10#13#3'has been modified. Save?'); + Strings^.Put(sNoName,'NONAME'); + Strings^.Put(sNormal,'Normal'); + Strings^.Put(sNormalText,'Normal text'); + Strings^.Put(sNotInList,'Input not in valid-list'); + Strings^.Put(sOpen,'Open'); + Strings^.Put(sOutOfMemory,'Not enough memory for this operation.'); + Strings^.Put(sOutOfUnNamedWindows,'Out of unnamed window numbers. Save or discard some unnamed files and try again.'); + Strings^.Put(sPasteNotPossible,'Wordwrap on: Paste not possible in current margins when at end of line.'); + Strings^.Put(sReformatDocument,'Reformat Document'); + Strings^.Put(sReformatNotPossible,'Paragraph reformat not possible while trying to wrap current line with current margins.'); + Strings^.Put(sReformattingTheDocument,'Reformatting the document:'); + Strings^.Put(sReplace,'Replace'); + Strings^.Put(sReplaceFile,'Replace file?'#13#10#13#3'%s'); + Strings^.Put(sReplaceNotPossible,'Wordwrap on: Replace not possible in current margins when at end of line.'); + Strings^.Put(sReplaceThisOccurence,'Replace this occurence?'); + Strings^.Put(sRightMargin,'Right Margin'); + Strings^.Put(sSaveAs,'Save As'); + Strings^.Put(sScrollbarIcons,'Scroll bar icons'); + Strings^.Put(sScrollbarPage,'Scroll bar page'); + Strings^.Put(sSearchStringNotFound,'Search string not found.'); + Strings^.Put(sSelectFormatStart,'Select Format Start'); + Strings^.Put(sSelectWhereToBegin,'Please select where to begin.'); + Strings^.Put(sSelected,'Selected'); + Strings^.Put(sSelectedDisabled,'Selected disabled'); + Strings^.Put(sSetting,'Setting:'); + Strings^.Put(sShortcut,'Shortcut'); + Strings^.Put(sShortcutSelected,'ShortcutSelected'); + Strings^.Put(sStaticText,'Static text'); + Strings^.Put(sTabSettings,'Tab Settings'); + Strings^.Put(sText,'Text'); + Strings^.Put(sTooManyFiles,'Too many files.'); + Strings^.Put(sTypeExitOnReturn,'Type EXIT to return...'); + Strings^.Put(sUnderline,'Underline'); + Strings^.Put(sUnknownDialog,'Unknown dialog requested!'); + Strings^.Put(sUntitled,'Untitled'); + Strings^.Put(sWarning,'Warning'); + Strings^.Put(sWindowList,'Window List'); + Strings^.Put(sWordWrapNotPossible,'Wordwrap on: Wordwrap not possible in current margins with continuous line.'); + Strings^.Put(sWordWrapOff,'You must turn on wordwrap before you can reformat.'); + Strings^.Put(smApr,'Apr'); + Strings^.Put(smAug,'Aug'); + Strings^.Put(smDec,'Dec'); + Strings^.Put(smFeb,'Feb'); + Strings^.Put(smJan,'Jan'); + Strings^.Put(smJul,'Jul'); + Strings^.Put(smJun,'Jun'); + Strings^.Put(smMar,'Mar'); + Strings^.Put(smMay,'May'); + Strings^.Put(smNov,'Nov'); + Strings^.Put(smOct,'Oct'); + Strings^.Put(smSep,'Sep'); +end; + +procedure InitResLabels; +begin + Labels^.Put(slAbout,'~A~bout'); + Labels^.Put(slAltF1,'Alt+F1'); + Labels^.Put(slAltF3Close,'~Alt+F3~ Close'); + Labels^.Put(slAltXExit,'~Alt-X~ Exit'); + Labels^.Put(slBackground,'~B~ackground'); + Labels^.Put(slCancel,'Cancel'); + Labels^.Put(slCascade,'C~a~scade'); + Labels^.Put(slCaseSensitive,'~C~ase sensitive'); + Labels^.Put(slChDir,'~C~hdir'); + Labels^.Put(slChangeDir,'~C~hange dir...'); + Labels^.Put(slClear,'C~l~ear'); + Labels^.Put(slClose,'~C~lose'); + Labels^.Put(slCloseAll,'Cl~o~se all'); + Labels^.Put(slColor,'~C~olor'); + Labels^.Put(slContents,'~C~ontents'); + Labels^.Put(slCopy,'~C~opy'); + Labels^.Put(slCtrlF1,'Ctrl+F1'); + Labels^.Put(slCurrentLine,'~C~urrent line'); + Labels^.Put(slCut,'Cu~t~'); + Labels^.Put(slDOSShell,'~D~OS shell'); + Labels^.Put(slDelete,'~D~elete'); + Labels^.Put(slDirectoryName,'Directory ~n~ame'); + Labels^.Put(slDirectoryTree,'Directory ~t~ree'); + Labels^.Put(slEdit,'~E~dit'); + Labels^.Put(slEntireDocument,'~E~ntire document'); + Labels^.Put(slExit,'E~x~it'); + Labels^.Put(slF10Menu,'~F10~ Menu'); + Labels^.Put(slF1Help,'~F1~ Help'); + Labels^.Put(slF3Open,'~F3~ Open'); + Labels^.Put(slFile,'~F~ile'); + Labels^.Put(slFiles,'~F~iles'); + Labels^.Put(slForeground,'~F~oreground'); + Labels^.Put(slGroup,'~G~roup'); + Labels^.Put(slHelp,'~H~elp'); + Labels^.Put(slIndex,'~I~ndex'); + Labels^.Put(slItem,'~I~tem'); + Labels^.Put(slLineNumber,'~L~ine number'); + Labels^.Put(slName,'~N~ame'); + Labels^.Put(slNew,'~N~ew'); + Labels^.Put(slNewText,'~N~ew text'); + Labels^.Put(slNext,'~N~ext'); + Labels^.Put(slNo,'~N~o'); + Labels^.Put(slOk,'O~k~'); + Labels^.Put(slOpen,'~O~pen'); + Labels^.Put(slOpenDots,'~O~pen...'); + Labels^.Put(slPaste,'~P~aste'); + Labels^.Put(slPrevious,'~P~revious'); + Labels^.Put(slPreviousTopic,'~P~revious topic'); + Labels^.Put(slPromptOnReplace,'~P~rompt on replace'); + Labels^.Put(slReformatDocument,'~R~eformat document'); + Labels^.Put(slReplace,'~R~eplace'); + Labels^.Put(slReplaceAll,'~R~eplace all'); + Labels^.Put(slRevert,'~R~evert'); + Labels^.Put(slSave,'~S~ave'); + Labels^.Put(slSaveAll,'Save a~l~l'); + Labels^.Put(slSaveAs,'S~a~ve as...'); + Labels^.Put(slSaveFileAs,'~S~ave file as'); + Labels^.Put(slShiftF1,'Shift+F1'); + Labels^.Put(slSizeMove,'~S~ize/Move'); + Labels^.Put(slTextToFind,'~T~ext to find'); + Labels^.Put(slTile,'~T~ile'); + Labels^.Put(slTopicSearch,'~T~opic search'); + Labels^.Put(slUndo,'~U~ndo'); + Labels^.Put(slUsingHelp,'~U~sing help'); + Labels^.Put(slWholeWordsOnly,'~W~hole words only'); + Labels^.Put(slWindow,'~W~indow'); + Labels^.Put(slWindows,'~W~indows'); + Labels^.Put(slYes,'~Y~es'); + Labels^.Put(slZoom,'~Z~oom'); + Labels^.Put(slAltF3,'Alt+F3'); + Labels^.Put(slAltX,'Alt+X'); + Labels^.Put(slF2,'F2'); + Labels^.Put(slF3,'F3'); + Labels^.Put(slF5,'F5'); + Labels^.Put(slF6,'F6'); + Labels^.Put(slCtrlDel,'Ctrl+Del'); + Labels^.Put(slCtrlF5,'Ctrl+F5'); + Labels^.Put(slCtrlIns,'Ctrl+Ins'); + Labels^.Put(slShiftDel,'Shift+Del'); + Labels^.Put(slShiftF6,'Shift+F6'); + Labels^.Put(slShiftIns,'Shift+Ins'); +end;