1366 lines
32 KiB
Plaintext
1366 lines
32 KiB
Plaintext
|
||
{ 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.
|
||
|