{ Copyright (c) 1989 by Borland International, Inc. } unit TCRun; { Turbo Pascal 5.5 object-oriented example run module. This unit is used by TCALC.PAS. See TCALC.DOC for an more information about this example. } {$N+,S-} interface uses Crt, Dos, TCUtil, TCLStr, TCScreen, TCHash, TCCell, TCCellSp, TCSheet, TCInput, TCParser, TCMenu; const FreeListItems = 1000; MenuHeapSpace = 1000; MaxSpreadsheets = (MinScreenRows - EmptyRowsAtTop - EmptyRowsAtBottom) div 4; LegalJustification = ['L', 'C', 'R']; HelpLine = 'F2\Save\F3\Load\F7\Formula\F8\AutoCalc\F9\Recalc\F10\Menu\Ins\Block\Alt-X\Exit'; TitleString = 'TurboCalc - Turbo Pascal Demo Program'; MainMenuString = 'Spreadsheet, Block, Column, Row, Format, Goto, Edit, Options, Quit'; SpreadsheetMenuString = 'Load, Save, Zap, Write, Open, Close, Next, Print'; OpenMenuString = 'Load, New'; BlockMenuString = 'Copy, Delete, Format, Restore default format'; ColumnMenuString = 'Insert, Delete, Width'; RowMenuString = 'Insert, Delete'; UtilityMenuString1 = 'Screen lines, Recalc, Formula display, Autocalc'; UtilityMenuString2 = 'Recalc, Formula display, Autocalc'; PromptFileLoad = 'File to load'; PromptGotoCell = 'Go to cell'; PromptCopyCell = 'Copy to cell'; PromptColLiteral = 'Copy formula columns literally'; PromptRowLiteral = 'Copy formula rows literally'; PromptCopySpreadsheet = 'Copy to spreadsheet number (0 = current)'; PromptFormatPlaces = 'Number of decimal places'; PromptFormatJustification = 'Justification - (L)eft, (C)enter, (R)ight'; PromptFormatDollar = 'Dollar format'; PromptFormatCommas = 'Put commas in numbers'; ErrFreeList = 'The free list is full'; MsgBlockCopy = 'Copying block'; type ProgramObject = object SSData, CurrSS : SpreadsheetPtr; TotalSheets : Byte; CellInput : InputField; MainMenu : Menu; SpreadsheetMenu : Menu; OpenMenu : Menu; BlockMenu : Menu; ColumnMenu : Menu; RowMenu : Menu; UtilityMenu : Menu; Stop : Boolean; constructor Init; destructor Done; procedure GetCommands; procedure SetDisplayAreas; procedure DisplayAll; function AddSheet(Name : PathStr) : Boolean; procedure DeleteSheet; end; var Vars : ProgramObject; procedure Run; implementation const RedrawYes = True; RedrawNo = False; {$F+} function RunHeapError(Size : Word) : Integer; { Prints an error if the heap runs out of memory } begin Scr.PrintError(ErrNoMemory); RunHeapError := 1; end; { RunHeapError } {$F-} procedure InitMenus; forward; constructor ProgramObject.Init; { Sets up the program } var Counter : Word; Good : Boolean; begin { ProgramObject.Init } if MaxAvail < MenuHeapSpace then Abort(ErrNoMemory); InitMenus; TotalSheets := 0; SSData := nil; CurrSS := nil; Stop := False; if ParamCount = 0 then { Load spreadsheets named on command line } begin if not AddSheet('') then Abort(ErrNoMemory); end else begin Counter := 1; repeat Good := AddSheet(ParamStr(Counter)); Inc(Counter); until (not Good) or (Counter > Min(ParamCount, MaxSpreadsheets)); end; SetDisplayAreas; DisplayAll; with CurrSS^ do begin MakeCurrent; DisplayCell(CurrPos); end; { with } end; { ProgramObject.Init } destructor ProgramObject.Done; { Releases all memory used by the program } begin CurrSS^.MakeNotCurrent; while SSData <> nil do begin CurrSS := SSData; SSData := SSData^.Next; with CurrSS^ do begin MakeCurrent; DisplayCell(CurrPos); CheckForSave; MakeNotCurrent; DisplayCell(CurrPos); Dispose(CurrSS, Done); end; { with } end; MainMenu.Done; SpreadsheetMenu.Done; OpenMenu.Done; BlockMenu.Done; ColumnMenu.Done; RowMenu.Done; UtilityMenu.Done; end; { ProgramObject.Done } function GetFormat(var Format : Byte) : Boolean; { Reads a format value from the keyboard } var Places : Byte; J : Justification; ESCPressed, Good, Dollar, Commas : Boolean; Ch : Char; begin GetFormat := False; Dollar := GetYesNo(PromptFormatDollar, ESCPressed); if ESCPressed then Exit; if Dollar then begin Places := 2; J := JRight; end else begin Places := GetNumber(PromptFormatPlaces, 0, Vars.CurrSS^.MaxDecimalPlaces, Good); if not Good then Exit; Ch := GetLegalChar(PromptFormatJustification, LegalJustification, ESCPressed); if ESCPressed then Exit; case Ch of 'L' : J := JLeft; 'C' : J := JCenter; 'R' : J := JRight; end; { case } end; Commas := GetYesNo(PromptFormatCommas, ESCPressed); if ESCPressed then Exit; Format := Places + (Ord(J) shl 4) + (Ord(Dollar) shl 6) + (Ord(Commas) shl 7); GetFormat := True; end; { GetFormat } procedure EditInput(Ch : Word; Editing : Boolean); { Edits the data on the input line } var Good, FirstEdit, Deleted : Boolean; P : CellPos; begin with Vars, CurrSS^ do begin if not CellInput.Init(1, 0, -1, 0, NotUpper) then Exit; with CellInput.InputData^ do begin if Editing then begin Good := True; CellHash.Search(CurrPos)^.EditString(MaxDecimalPlaces, CellInput.InputData) end else Good := FromString(Chr(Ch)); if not Good then begin CellInput.Done; Exit; end; FirstEdit := True; Parser.Init(@CellHash, CellInput.InputData, MaxCols, MaxRows); repeat if FirstEdit then CellInput.Edit(0) else CellInput.Edit(Parser.Position); if Length > 0 then begin Parser.Parse; if Parser.TokenError = 0 then begin DeleteCell(CurrPos, Deleted); Good := AddCell(Parser.CType, CurrPos, Parser.ParseError, Parser.ParseValue, CellInput.InputData); end; end; FirstEdit := False; until (Length = 0) or (Parser.TokenError = 0); if Length > 0 then begin SetChanged(WasChanged); if AutoCalc then Update(DisplayYes); P := CurrPos; for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do DisplayCell(P); end; CellInput.InputArea.Clear; end; { with } CellInput.Done; DisplayMemory; end; { with } end; { EditInput } procedure OpenSpreadsheet(Name : String); { Opens a new spreadsheet } begin with Vars do begin if not AddSheet(Name) then Exit; SetDisplayAreas; DisplayAll; with CurrSS^ do begin MakeCurrent; DisplayCell(CurrPos); end; { with } end; { with } end; { OpenSpreadsheet } procedure ClearCurrBlock; { Turns off the block and redisplays the cells in it } begin with Vars.CurrSS^ do begin if BlockOn then begin BlockOn := False; DisplayBlock(CurrBlock); end; end; end; { ClearCurrBlock } {$F+} procedure ReplaceSpreadsheet; { Load a spreadsheet over the current one } var S : PathStr; ESCPressed : Boolean; begin with Vars.CurrSS^ do begin S := ReadString(PromptFileLoad, Pred(SizeOf(PathStr)), ESCPressed); if S = '' then Exit; CheckForSave; Done; if FromFile(S) then begin SetChanged(NotChanged); SetScreenColStart(1); SetScreenRowStart(1); Display; MakeCurrent; DisplayCell(CurrPos); end; end; { with } end; { ReplaceSpreadsheet } procedure NameSaveSpreadsheet; { Save a spreadsheet to a file other that its default } var St : PathStr; ESCPressed : Boolean; begin with Vars.CurrSS^ do begin St := ReadString(PromptFileSave, Pred(SizeOf(PathStr)), ESCPressed); if St = '' then Exit; if FileExists(St) then begin if not GetYesNo(PromptOverwriteFile, ESCPressed) then Exit; end; ToFile(St); DisplayFileName; end; { with } end; { NameSaveSpreadsheet } procedure SaveCurrSpreadsheet; { Save a spreadsheet to its default file } begin with Vars.CurrSS^ do begin if FileName = '' then NameSaveSpreadsheet else ToFile(FileName); end; { with } end; { SaveCurrSpreadsheet } procedure ZapSpreadsheet; { Clear the current spreadsheet from memory } var S : PathStr; begin with Vars.CurrSS^ do begin CheckForSave; S := FileName; Done; Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, DefaultDefaultColWidth); MakeCurrent; FileName := S; SetScreenColStart(1); SetScreenRowStart(1); Display; end; { with } end; { ZapSpreadsheet } procedure CloseSpreadsheet; { Delete a spreadsheet, closing the window that it is in } begin with Vars, CurrSS^ do begin if TotalSheets = 1 then Exit; DeleteSheet; end; { with } end; { CloseSpreadsheet } procedure NextSpreadsheet; { Move to the next spreadsheet } begin with Vars do begin if TotalSheets = 1 then Exit; with CurrSS^ do begin MakeNotCurrent; DisplayCell(CurrPos); end; { with } CurrSS := CurrSS^.Next; if CurrSS = nil then CurrSS := SSData; with CurrSS^ do begin MakeCurrent; DisplayCell(CurrPos); end; { with } end; { with } end; { NextSpreadsheet } procedure NewSpreadsheet; { Create a new spreadsheet, opening a window for it and loading it } var S : PathStr; ESCPressed : Boolean; begin with Vars do begin if TotalSheets >= MaxSpreadsheets then Exit; S := ReadString(PromptFileLoad, Pred(SizeOf(PathStr)), ESCPressed); if S = '' then Exit; OpenSpreadsheet(S); end; { with } end; { NewSpreadsheet } procedure NewBlankSpreadsheet; { Create a new blank spreadsheet, opening a window for it } begin with Vars do begin if TotalSheets >= MaxSpreadsheets then Exit; OpenSpreadsheet(''); end; { with } end; { NewBlankSpreadsheet } procedure PrintSpreadsheet; { Print a spreadsheet to a file or a printer } begin Vars.CurrSS^.Print; end; { PrintSpreadsheet } procedure CopyBlock; { Copy a block of cells from one spreadsheet to the same or a different spreadsheet } var P, N, C : CellPos; Good, ESCPressed, ColLit, RowLit, AnyChanged, Deleted : Boolean; CP : CellPtr; L : LStringPtr; CopyTo : SpreadsheetPtr; CopySheet : Byte; Counter : Word; begin with Vars, CurrSS^, CurrBlock do begin if not BlockOn then Exit; if TotalSheets > 1 then CopySheet := GetNumber(PromptCopySpreadsheet, 0, TotalSheets, Good) else CopySheet := 1; if not Good then Exit; if not GetCellPos(PromptCopyCell, MaxCols, MaxRows, ColSpace, RowNumberSpace, P) then Exit; ColLit := GetYesNo(PromptColLiteral, ESCPressed); if ESCPressed then Exit; RowLit := GetYesNo(PromptRowLiteral, ESCPressed); if ESCPressed then Exit; Scr.PrintMessage(MsgBlockCopy); if CopySheet = 0 then CopyTo := CurrSS else begin CopyTo := SSData; for Counter := 2 to CopySheet do CopyTo := CopyTo^.Next; end; AnyChanged := False; C.Row := P.Row; N.Row := Start.Row; L := New(LStringPtr, Init); Good := L <> nil; while Good and (N.Row <= Stop.Row) do begin C.Col := P.Col; N.Col := Start.Col; while Good and (N.Col <= Stop.Col) do begin if (Longint(P.Col) + N.Col - Start.Col <= MaxCols) and (Longint(P.Row) + N.Row - Start.Row <= MaxRows) then begin CopyTo^.DeleteCell(C, Deleted); if Deleted then AnyChanged := True; CP := CellHash.Search(N); if CP <> Empty then begin AnyChanged := True; with CP^ do Good := CopyTo^.AddCell(CellType, C, HasError, CurrValue, CopyString(ColLit, RowLit, Longint(C.Col) - N.Col, L)); if Good and ((not ColLit) or (not RowLit)) then begin CP := CopyTo^.CellHash.Search(C); if CP^.ShouldUpdate then begin if not ColLit then FixFormulaCol(CP, Longint(C.Col) - N.Col, MaxCols, MaxRows); if not RowLit then FixFormulaRow(CP, Longint(C.Row) - N.Row, MaxCols, MaxRows); end; end; end; end; Inc(C.Col); Inc(N.Col); end; Inc(C.Row); Inc(N.Row); end; if AnyChanged then begin if CopySheet = 0 then BlockOn := False; with CopyTo^ do begin SetLastPos(LastPos); SetChanged(WasChanged); if AutoCalc then Update(DisplayNo); DisplayAllCells; DisplayMemory; end; { with } if CopySheet <> 0 then ClearCurrBlock; end else ClearCurrBlock; Scr.ClearMessage; end; { with } if L <> nil then Dispose(L, Done); end; { CopyBlock } procedure DeleteBlock; { Delete a block of cells } var Deleted : Boolean; begin with Vars.CurrSS^, CurrBlock do begin if not BlockOn then Exit; DeleteBlock(CurrBlock, Deleted); if Deleted then begin BlockOn := False; SetLastPos(LastPos); SetChanged(WasChanged); if AutoCalc then Update(DisplayNo); DisplayMemory; DisplayAllCells; end else ClearCurrBlock; end; { with } end; { DeleteBlock } procedure FormatBlock; { Format a block of cells } var Format : Byte; begin with Vars.CurrSS^ do begin if not BlockOn then Exit; if not GetFormat(Format) then Exit; with CurrBlock do begin if not FormatHash.Add(Start, Stop, Format) then Exit; SetChanged(WasChanged); DisplayAllCells; DisplayMemory; end; { with } end; { with } end; { FormatBlock } procedure FormatDefault; { Change the format of a block of cells to the default } begin with Vars.CurrSS^ do begin if not BlockOn then Exit; with CurrBlock do begin if not FormatHash.Delete(Start, Stop) then Exit; SetChanged(WasChanged); DisplayAllCells; DisplayMemory; end; { with } end; { with } end; { FormatDefault } procedure ColInsert; { Insert a column into the spreadsheet } begin Vars.CurrSS^.InsertColumn; end; { ColInsert } procedure ColDelete; { Delete a column from the spreadsheet } begin Vars.CurrSS^.DeleteColumn; end; { ColDelete } procedure ChangeColWidth; { Change the width of a column } begin Vars.CurrSS^.ChangeWidth; end; { ChangeColWidth } procedure RowInsert; { Insert a row into the spreadsheet } begin Vars.CurrSS^.InsertRow; end; { RowInsert } procedure RowDelete; { Delete a row from the spreadsheet } begin Vars.CurrSS^.DeleteRow; end; { RowDelete } procedure ToggleMaxLines; { Toggle 43/50-line mode } begin with Vars do begin Scr.ToggleMaxLinesMode; SetCursor(NoCursor); SetDisplayAreas; DisplayAll; end; { with } end; { ToggleMaxLines } procedure Recalc; { Recalculate all of the cells } begin Vars.CurrSS^.Update(DisplayYes); end; { Recalc } procedure ToggleFormulas; { Toggle formula display on and off } begin with Vars.CurrSS^ do ToggleFormulaDisplay; end; { ToggleFormulas } procedure ToggleAutoCalc; { Toggle AutoCalc on and off } begin with Vars.CurrSS^ do begin if AutoCalc then begin AutoCalc := False; DisplayInfo; end else begin AutoCalc := True; DisplayInfo; Update(DisplayYes); end; end; end; { ToggleAutoCalc } procedure FormatCell; { Format a single cell } var Format : Byte; P : CellPos; CP : CellPtr; Good : Boolean; begin with Vars.CurrSS^ do begin if not GetFormat(Format) then Exit; if not FormatHash.Add(CurrPos, CurrPos, Format) then Exit; CP := CellHash.Search(CurrPos); SetChanged(WasChanged); OverwriteHash.Delete(CurrPos); if CP <> Empty then Good := OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash, WidthHash, LastPos, MaxCols, GetColWidth, DisplayFormulas)); P := CurrPos; for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do DisplayCell(P); DisplayMemory; end; { with } end; { FormatCell } procedure GotoCell; { Go to a selected cell } var P, OldPos : CellPos; begin with Vars.CurrSS^ do begin if not GetCellPos(PromptGotoCell, MaxCols, MaxRows, ColSpace, RowNumberSpace, P) then Exit; if not ScreenBlock.CellInBlock(P) then begin CurrPos := P; SetScreenColStart(CurrPos.Col); SetScreenRowStart(CurrPos.Row); Display; end else begin OldPos := CurrPos; CurrPos := P; DisplayCell(OldPos); DisplayCell(CurrPos); end; end; { with } end; { GotoCell } procedure EditCell; { Edit the current cell } begin EditInput(0, EditYes); end; { EditCell } procedure Quit; { Exit from the program } begin Vars.Stop := True; end; { Quit } {$F-} procedure ExtendCurrBlock(Redraw : Boolean); { Extend the current block and redraw any cells that are affected } var OldBlock : Block; begin with Vars.CurrSS^ do begin if BlockOn then begin Move(CurrBlock, OldBlock, SizeOf(CurrBlock)); if CurrBlock.ExtendTo(CurrPos) then begin if Redraw then DisplayBlockDiff(OldBlock, CurrBlock); end else ClearCurrBlock; end; end; { with } end; { ExtendCurrBlock } procedure ToggleCurrBlock; { Turn the block on and off } begin with Vars.CurrSS^ do begin if not BlockOn then begin BlockOn := True; CurrBlock.Init(CurrPos); end else ClearCurrBlock; end; { with } end; { ToggleCurrBlock } procedure RemoveCell; { Delete a cell } var P : CellPos; Deleted : Boolean; begin with Vars.CurrSS^ do begin DeleteCell(CurrPos, Deleted); if Deleted then begin SetLastPos(CurrPos); SetChanged(WasChanged); if AutoCalc then Update(DisplayYes); P.Row := CurrPos.Row; for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do DisplayCell(P); DisplayMemory; end; end; { with } end; { RemoveCell } procedure MoveHome; { Move to the home position (1, 1) } var OldPos : CellPos; begin with Vars.CurrSS^ do begin OldPos := CurrPos; CurrPos.Col := 1; CurrPos.Row := 1; if not ScreenBlock.CellInBlock(CurrPos) then begin ExtendCurrBlock(RedrawNo); SetScreenColStart(1); SetScreenRowStart(1); SetBlankArea; Display; end else begin ExtendCurrBlock(RedrawYes); DisplayCell(OldPos); DisplayCell(CurrPos); end; end; { with } end; { MoveHome } procedure MoveEnd; { Move to the last position used } var OldPos : CellPos; begin with Vars.CurrSS^ do begin OldPos := CurrPos; CurrPos := LastPos; if not ScreenBlock.CellInBlock(CurrPos) then begin ExtendCurrBlock(RedrawNo); SetScreenColStop(CurrPos.Col); SetScreenRowStop(CurrPos.Row); SetBlankArea; Display; end else begin ExtendCurrBlock(RedrawYes); DisplayCell(OldPos); DisplayCell(CurrPos); end; end; { with } end; { MoveEnd } procedure MoveUp; { Move up a row } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Row > 1 then begin OldPos := CurrPos; Dec(CurrPos.Row); ExtendCurrBlock(RedrawYes); if CurrPos.Row < ScreenBlock.Start.Row then begin DisplayCell(OldPos); SetScreenRowStart(CurrPos.Row); DisplayRows; DisplayArea.Scroll(Down, 1); DisplayRow(CurrPos.Row); end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MoveUp } procedure MoveDown; { Move down a row } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Row < MaxRows then begin OldPos := CurrPos; Inc(CurrPos.Row); if CurrPos.Row > ScreenBlock.Stop.Row then begin ExtendCurrBlock(RedrawNo); DisplayCell(OldPos); SetScreenRowStop(CurrPos.Row); DisplayRows; DisplayArea.Scroll(Up, 1); DisplayRow(CurrPos.Row); end else begin ExtendCurrBlock(RedrawYes); DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MoveDown } procedure MovePgUp; { Move up a page } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Row > 1 then begin OldPos := CurrPos; CurrPos.Row := Max(1, Longint(CurrPos.Row) - TotalRows); ExtendCurrBlock(RedrawNo); if CurrPos.Row < ScreenBlock.Start.Row then begin SetScreenRowStart(CurrPos.Row); DisplayRows; DisplayAllCells; end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MovePgUp } procedure MovePgDn; { Move down a page } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Row < MaxRows then begin OldPos := CurrPos; CurrPos.Row := Min(MaxRows, Longint(CurrPos.Row) + TotalRows); ExtendCurrBlock(RedrawNo); if CurrPos.Row > ScreenBlock.Start.Row then begin SetScreenRowStart(CurrPos.Row); DisplayRows; DisplayAllCells; end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MovePgDn } procedure MoveLeft; { Move left a column } var C : Word; OldPos : CellPos; OldSCol : Word; begin with Vars.CurrSS^ do begin if CurrPos.Col > 1 then begin OldPos := CurrPos; Dec(CurrPos.Col); ExtendCurrBlock(RedrawYes); if CurrPos.Col < ScreenBlock.Start.Col then begin OldSCol := ScreenBlock.Start.Col; C := GetColStart(1); DisplayCell(OldPos); SetScreenColStart(CurrPos.Col); SetBlankArea; DisplayCols; DisplayArea.Scroll(Right, GetColStart(OldSCol - ScreenBlock.Start.Col) - GetColStart(0)); if not NoBlankArea then BlankArea.Clear; for C := ScreenBlock.Start.Col to CurrPos.Col do DisplayCol(C); end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MoveLeft } procedure MoveRight; { Move right a column } var C : Word; OldPos : CellPos; SaveColStart : array[0..79] of Byte; OldSCol : Word; begin with Vars.CurrSS^ do begin if CurrPos.Col < MaxCols then begin OldPos := CurrPos; Inc(CurrPos.Col); if CurrPos.Col > ScreenBlock.Stop.Col then begin ExtendCurrBlock(RedrawNo); for C := 0 to Pred(MaxScreenCols) do SaveColStart[C] := GetColStart(C); OldSCol := ScreenBlock.Start.Col; DisplayCell(OldPos); C := ColWidth(ScreenBlock.Start.Col); SetScreenColStop(CurrPos.Col); SetBlankArea; DisplayCols; DisplayArea.Scroll(Left, SaveColStart[ScreenBlock.Start.Col - OldSCol] - ColStart^[0]); if not NoBlankArea then BlankArea.Clear; for C := CurrPos.Col to ScreenBlock.Stop.Col do DisplayCol(C); end else begin ExtendCurrBlock(RedrawYes); DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MoveRight } procedure MovePgLeft; { Move left a page } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Col > 1 then begin OldPos := CurrPos; CurrPos.Col := Max(1, Pred(ScreenBlock.Start.Col)); ExtendCurrBlock(RedrawNo); if CurrPos.Col < ScreenBlock.Start.Col then begin SetScreenColStop(CurrPos.Col); SetBlankArea; DisplayCols; if not NoBlankArea then BlankArea.Clear; DisplayAllCells; end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MovePgLeft } procedure MovePgRight; { Move right a page } var OldPos : CellPos; begin with Vars.CurrSS^ do begin if CurrPos.Col < MaxCols then begin OldPos := CurrPos; CurrPos.Col := Min(MaxCols, Succ(ScreenBlock.Stop.Col)); ExtendCurrBlock(RedrawNo); if CurrPos.Col > ScreenBlock.Start.Col then begin SetScreenColStart(CurrPos.Col); SetBlankArea; DisplayCols; if not NoBlankArea then BlankArea.Clear; DisplayAllCells; end else begin DisplayCell(OldPos); DisplayCell(CurrPos); end; end; end; { with } end; { MovePgRight } procedure HandleInput(Ch : Word); { Process the initial input from the keyboard } begin EditInput(Ch, EditNo); end; { HandleInput } procedure ProgramObject.GetCommands; { Read the keyboard and process the next command } var Ch : Word; begin repeat CurrSS^.DisplayCellData; ClearInputBuffer; Ch := GetKey; case Ch of F2 : SaveCurrSpreadsheet; AltF2 : NameSaveSpreadsheet; F3 : ReplaceSpreadsheet; AltF3 : NewSpreadsheet; F4 : DeleteSheet; F6 : NextSpreadsheet; F7 : ToggleFormulas; F8 : ToggleAutoCalc; F9 : Recalc; F10 : MainMenu.RunMenu; AltX : Stop := True; InsKey : ToggleCurrBlock; DelKey : RemoveCell; HomeKey : MoveHome; EndKey : MoveEnd; UpKey : MoveUp; DownKey : MoveDown; LeftKey : MoveLeft; RightKey : MoveRight; PgUpKey : MovePgUp; PgDnKey : MovePgDn; CtrlLeftKey : MovePgLeft; CtrlRightKey : MovePgRight; Ord(' ')..Ord('~') : HandleInput(Ch); end; until Stop; end; { ProgramObject.GetCommands } procedure ProgramObject.SetDisplayAreas; { Set the display areas of the various spreadsheets } var S : SpreadsheetPtr; Total, StartRow, Amt : Word; begin S := SSData; StartRow := Succ(EmptyRowsAtTop); Amt := (Scr.CurrRows - EmptyRowsAtTop - EmptyRowsAtBottom) div TotalSheets; Total := 1; repeat if S^.Next = nil then Amt := Succ(Scr.CurrRows - EmptyRowsAtBottom - StartRow); S^.SetAreas(Total, 1, StartRow, Scr.CurrCols, Pred(StartRow + Amt)); Inc(StartRow, Amt); S := S^.Next; Inc(Total); until S = nil; end; { ProgramObject.SetDisplayAreas } procedure ProgramObject.DisplayAll; { Display all of the spreadsheets } var S : SpreadsheetPtr; begin TextAttr := Colors.BlankColor; ClrScr; WriteColor(TitleString, Colors.TitleColor); Scr.PrintHelpLine(HelpLine); WriteXY(MemoryString, Scr.CurrCols - Length(MemoryString) - 5, 1, Colors.PromptColor); S := SSData; repeat S^.Display; S := S^.Next; until S = nil; end; { ProgramObject.DisplayAll } function ProgramObject.AddSheet(Name : PathStr) : Boolean; { Add a new spreadsheet } var A, S : SpreadsheetPtr; Good, AllocatingNext : Boolean; begin AddSheet := False; if TotalSheets = MaxSpreadsheets then Exit; S := SSData; while (S <> nil) and (S^.Next <> nil) do S := S^.Next; if SSData <> nil then begin A := S; New(S^.Next); S := S^.Next; AllocatingNext := True; end else begin New(S); AllocatingNext := False; end; if S = nil then Exit; if Name = '' then Good := S^.Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, DefaultDefaultColWidth) else Good := S^.FromFile(Name); if not Good then begin Dispose(S); if AllocatingNext then A^.Next := nil; Exit; end; if SSData = nil then SSData := S; if CurrSS <> nil then CurrSS^.Current := False; CurrSS := S; Inc(TotalSheets); S^.Next := nil; AddSheet := True; end; { ProgramObject.AddSheet } procedure ProgramObject.DeleteSheet; { Delete a spreadsheet } var S : SpreadsheetPtr; begin if TotalSheets > 1 then begin S := SSData; if S = CurrSS then SSData := S^.Next else begin while S^.Next <> CurrSS do S := S^.Next; S^.Next := S^.Next^.Next; end; end; with CurrSS^ do begin CheckForSave; Done; end; { with } if TotalSheets > 1 then begin FreeMem(CurrSS, SizeOf(Spreadsheet)); Dec(TotalSheets); CurrSS := SSData; end else CurrSS^.Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, DefaultDefaultColWidth); SetDisplayAreas; DisplayAll; with CurrSS^ do begin MakeCurrent; DisplayCell(CurrPos); end; { with } end; { ProgramObject.DeleteSheet } procedure InitMenus; { Initialize the menu items } var Good : Boolean; P : Word; begin with Vars do begin with MainMenu do begin Init(MainMenuString, nil); Good := AddItemMenu(@SpreadsheetMenu); Good := AddItemMenu(@BlockMenu); Good := AddItemMenu(@ColumnMenu); Good := AddItemMenu(@RowMenu); Good := AddItemProc(FormatCell); Good := AddItemProc(GotoCell); Good := AddItemProc(EditCell); Good := AddItemMenu(@UtilityMenu); Good := AddItemProc(Quit); end; { with } with SpreadsheetMenu do begin Init(SpreadsheetMenuString, @MainMenu); Good := AddItemProc(Replacespreadsheet); Good := AddItemProc(SaveCurrSpreadsheet); Good := AddItemProc(ZapSpreadsheet); Good := AddItemProc(NameSaveSpreadsheet); Good := AddItemMenu(@OpenMenu); Good := AddItemProc(CloseSpreadsheet); Good := AddItemProc(NextSpreadsheet); Good := AddItemProc(PrintSpreadsheet); end; { with } with OpenMenu do begin Init(OpenMenuString, @SpreadsheetMenu); Good := AddItemProc(NewSpreadsheet); Good := AddItemProc(NewBlankSpreadsheet); end; { with } with BlockMenu do begin Init(BlockMenuString, @MainMenu); Good := AddItemProc(CopyBlock); Good := AddItemProc(DeleteBlock); Good := AddItemProc(FormatBlock); Good := AddItemProc(FormatDefault); end; { with } with ColumnMenu do begin Init(ColumnMenuString, @MainMenu); Good := AddItemProc(ColInsert); Good := AddItemProc(ColDelete); Good := AddItemProc(ChangeColWidth); end; { with } with RowMenu do begin Init(RowMenuString, @MainMenu); Good := AddItemProc(RowInsert); Good := AddItemProc(RowDelete); end; { with } with UtilityMenu do begin if Scr.VideoType >= MCGA then begin Init(UtilityMenuString1, @MainMenu); Good := AddItemProc(ToggleMaxLines); end else Init(UtilityMenuString2, @MainMenu); Good := AddItemProc(Recalc); Good := AddItemProc(ToggleFormulas); Good := AddItemProc(ToggleAutoCalc); end; { with } end; { with } end; { InitMenus } procedure Run; { The main part of the program - it sets up the spreadsheets, reads commands, and them releases all of the memory that it used } begin SetCursor(NoCursor); with Vars do begin Init; GetCommands; Done; end; end; { Run } begin CheckBreak := False; FreeMin := FreeListItems shl 3; HeapError := @RunHeapError; end.