-- GCellToolImpl.mesa -- last edit July 10, 1984 9:42:03 pm PDT DIRECTORY Commander USING[CommandProc, Register], EasyTool USING[DefineItemsProc, DefineTool, ItemHandle], Expressions USING[ParseExpression, ParseIdentifier, SyntaxError], GCell USING[GCellItemDescriptor, GCellItemJustification, GCellItemMode, GCellItemRowColSumMode, GCellItemValueMode, GetGCellContents, GetItemSelection, SetGCellContents], MessageWindow USING[Append, Blink], NewCalcGlobal USING[Document], Rope USING[Equal, ROPE], StructureNodes USING[StructureNode]; GCellToolImpl: MONITOR IMPORTS Commander, GCell, EasyTool, Expressions, MessageWindow, Rope EXPORTS GCell = BEGIN ToolInstance: TYPE = REF ToolBody; ToolBody: TYPE = RECORD [ document: NewCalcGlobal.Document, itemDescriptors: ItemSequence, nActiveItems: REF CARDINAL ]; ItemSequence: TYPE = REF ItemSequenceBody; ItemSequenceBody: TYPE = RECORD[SEQUENCE maxNItems: CARDINAL OF ItemDisplay]; ItemDisplay: TYPE = REF ItemDisplayBody; ItemDisplayBody: TYPE = RECORD[ tool: ToolInstance, j: CARDINAL, active: BOOLEAN, mode: GCell.GCellItemMode, modeText: REF Rope.ROPE, justification: GCell.GCellItemJustification, justificationText: REF Rope.ROPE, rowSumMode: GCell.GCellItemRowColSumMode, rowSumModeText: REF Rope.ROPE, colSumMode: GCell.GCellItemRowColSumMode, colSumModeText: REF Rope.ROPE, valueMode: GCell.GCellItemValueMode, valueModeText: REF Rope.ROPE, idText: REF Rope.ROPE, textText: REF Rope.ROPE, zeroValTextText: REF Rope.ROPE ]; ModeTextSize: Rope.ROPE ← "showValue"; JustificationTextSize: Rope.ROPE ← "rightDecimal"; rowSumModeTextSize: Rope.ROPE ← "noEffect"; colSumModeTextSize: Rope.ROPE ← "noEffect"; valueModeTextSize: Rope.ROPE ← "expression"; IdTextSize: Rope.ROPE ← "lots of text, ver long rope etc more space"; TextTextSize: Rope.ROPE ← "lots of text, ver long rope etc more space"; ZVTextSize: Rope.ROPE ← "lots of text, ver long rope etc more space"; -- build an instance of the tool MakeAGCellToolInstance: PUBLIC ENTRY PROCEDURE[document: NewCalcGlobal.Document] = BEGIN NItems: CARDINAL = 20; sequence: ItemSequence ← NEW[ItemSequenceBody[NItems]]; instance: ToolInstance ← NEW[ToolBody ← [document, sequence, NEW[CARDINAL ←0]]]; DefineDisplayItems: EasyTool.DefineItemsProc = BEGIN colDescList: LIST OF EasyTool.ItemHandle ← NIL; lastOnColDescList: LIST OF EasyTool.ItemHandle; AppendToColumnList: PROCEDURE[item: EasyTool.ItemHandle] = BEGIN new: LIST OF EasyTool.ItemHandle ← LIST[item]; IF colDescList = NIL THEN colDescList ← lastOnColDescList ← new ELSE {lastOnColDescList.rest ← new; lastOnColDescList ← new}; END; AppendToColumnList[defineRow[LIST[ defineButton["Get a cell", GetACell], defineFiller[5, 5], defineButton["Set a cell", SetACell], defineFiller[5, 5], defineItem[ , "nItems", , instance.nActiveItems]]]]; AppendToColumnList[defineFiller[1, 10]]; FOR J: CARDINAL IN [0..NItems) DO AppendToColumnList[defineFiller[1, 10]]; AppendToColumnList[defineRow[LIST[ defineButton["I", InsertItem, sequence[J]], defineButton["D", DeleteItem, sequence[J]], defineFiller[15, 1], defineButton["M", StepItemMode, sequence[J]], defineItem[ , "m", , sequence[J].modeText, ModeTextSize, TRUE], defineFiller[15, 1], defineButton["J", StepItemJustification, sequence[J]], defineItem[ , "j", , sequence[J].justificationText, JustificationTextSize, TRUE], defineButton["RSM", StepItemRowSumMode, sequence[J]], defineItem[ , "rsm", , sequence[J].rowSumModeText, rowSumModeTextSize, TRUE], defineButton["CSM", StepItemColSumMode, sequence[J]], defineItem[ , "csm", , sequence[J].colSumModeText, colSumModeTextSize, TRUE], defineButton["VM", StepItemValueMode, sequence[J]], defineItem[ , "vm", , sequence[J].valueModeText, valueModeTextSize, TRUE]]]]; AppendToColumnList[defineRow[LIST[ defineFiller[15, 1], defineItem[ , "id", , sequence[J].idText, IdTextSize, TRUE]]]]; AppendToColumnList[defineRow[LIST[ defineFiller[15, 1], defineItem[ , "exp", , sequence[J].textText, TextTextSize, TRUE]]]]; AppendToColumnList[defineRow[LIST[ defineFiller[15, 1], defineItem[ , "zvt", , sequence[J].zeroValTextText, ZVTextSize, TRUE]]]]; ENDLOOP; RETURN[defineColumn[colDescList]]; END; FOR J: CARDINAL IN [0..NItems) DO sequence[J] ← NEW[ItemDisplayBody ← [instance, J, FALSE, showText, NEW[Rope.ROPE ← " "], left, NEW[Rope.ROPE ← " "], addVal, NEW[Rope.ROPE ← " "], addVal, NEW[Rope.ROPE ← " "], expression, NEW[Rope.ROPE ← " "], NEW[Rope.ROPE ← " "], NEW[Rope.ROPE ← " "], NEW[Rope.ROPE ← " "]]]; ENDLOOP; [] ← EasyTool.DefineTool["Cell Tool", instance, DefineDisplayItems]; END; -- global actions GetACell: ENTRY PROCEDURE[data: REF ANY] = BEGIN tool: ToolInstance ← NARROW[data]; gcSn: StructureNodes.StructureNode; ReceiveTheItems: PROCEDURE[nItems: CARDINAL, getOneItem: PROCEDURE RETURNS[GCell.GCellItemDescriptor]] = BEGIN FOR J: CARDINAL IN [0..nItems) DO desc: GCell.GCellItemDescriptor← getOneItem[]; tool.itemDescriptors[J].active ← TRUE; tool.itemDescriptors[J].mode ← desc.mode; ShowItemMode[tool.itemDescriptors[J]]; tool.itemDescriptors[J].justification ← desc.justification; ShowItemJustification[tool.itemDescriptors[J]]; tool.itemDescriptors[J].rowSumMode ← desc.rowSumMode; ShowItemRowSumMode[tool.itemDescriptors[J]]; tool.itemDescriptors[J].colSumMode ← desc.colSumMode; ShowItemColSumMode[tool.itemDescriptors[J]]; tool.itemDescriptors[J].valueMode ← desc.valueMode; ShowItemValueMode[tool.itemDescriptors[J]]; tool.itemDescriptors[J].idText↑ ← desc.id; tool.itemDescriptors[J].textText↑ ← desc.text; tool.itemDescriptors[J].zeroValTextText↑ ← desc.zeroValText; tool.nActiveItems↑ ← nItems; ENDLOOP; END; FOR J: CARDINAL IN [0..tool.itemDescriptors.maxNItems) DO NilAnItem[tool.itemDescriptors[J]] ENDLOOP; tool.nActiveItems↑ ← 0; [ , gcSn, ] ← GCell.GetItemSelection[]; -- really a call on NewCalcImpl IF gcSn = NIL THEN RETURN; GCell.GetGCellContents[gcSn, ReceiveTheItems, TRUE]; END; SetACell: ENTRY PROCEDURE[data: REF ANY] = BEGIN tool: ToolInstance ← NARROW[data]; gcSn: StructureNodes.StructureNode; j: CARDINAL ← 0; SendOneItem: PROCEDURE RETURNS[GCell.GCellItemDescriptor] = BEGIN desc: GCell.GCellItemDescriptor ← [ mode: tool.itemDescriptors[j].mode, justification: tool.itemDescriptors[j].justification, rowSumMode: tool.itemDescriptors[j].rowSumMode, colSumMode: tool.itemDescriptors[j].colSumMode, valueMode: tool.itemDescriptors[j].valueMode, id: tool.itemDescriptors[j].idText↑, text: tool.itemDescriptors[j].textText↑, zeroValText:tool.itemDescriptors[j].zeroValTextText↑ ]; j ← j + 1; RETURN[desc]; END; BEGIN -- allow for abort exit FOR J: CARDINAL IN [0..tool.nActiveItems↑) DO -- make sure there will be no "hidden" parse errors SELECT tool.itemDescriptors[J].mode FROM showText => NULL; showId, showExp, showValue, noShow => BEGIN IF tool.itemDescriptors[J].mode # showId AND NOT tool.itemDescriptors[J].idText↑ = NIL AND NOT Rope.Equal[tool.itemDescriptors[J].idText↑, ""] AND NOT Rope.Equal[tool.itemDescriptors[J].idText↑, " "] THEN [] ← Expressions.ParseIdentifier[tool.itemDescriptors[J].idText↑ ! Expressions.SyntaxError => BEGIN MessageWindow.Append[ message: "syntax error in identifier, text is ", clearFirst: TRUE]; MessageWindow.Append[ message: tool.itemDescriptors[J].idText↑, clearFirst: FALSE]; MessageWindow.Blink[]; GOTO abort; END]; [] ← Expressions.ParseExpression[tool.itemDescriptors[J].textText↑ ! Expressions.SyntaxError => BEGIN MessageWindow.Append[ message: "syntax error in expression, text is ", clearFirst: TRUE]; MessageWindow.Append[ message: tool.itemDescriptors[J].textText↑, clearFirst: FALSE]; MessageWindow.Blink[]; GOTO abort; END]; END; ENDCASE => ERROR; ENDLOOP; [ , gcSn, ] ← GCell.GetItemSelection[]; -- really a call on NewCalcImpl IF gcSn = NIL THEN RETURN; j ← 0; GCell.SetGCellContents[gcSn, tool.nActiveItems↑, SendOneItem, TRUE]; EXITS abort => NULL; END END; -- item button procs InsertItem: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; itemJ: CARDINAL ← item.j; IF item.j > 0 AND NOT item.tool.itemDescriptors[item.j-1].active THEN RETURN; IF item.tool.nActiveItems↑ = item.tool.itemDescriptors.maxNItems THEN RETURN; FOR J: CARDINAL DECREASING IN [itemJ..item.tool.nActiveItems↑] DO item.tool.itemDescriptors[J+1].mode ← item.tool.itemDescriptors[J].mode; item.tool.itemDescriptors[J+1].modeText↑ ← item.tool.itemDescriptors[J].modeText↑; item.tool.itemDescriptors[J+1].justification ← item.tool.itemDescriptors[J].justification; item.tool.itemDescriptors[J+1].justificationText↑ ← item.tool.itemDescriptors[J].justificationText↑; item.tool.itemDescriptors[J+1].idText↑ ← item.tool.itemDescriptors[J].idText↑; item.tool.itemDescriptors[J+1].textText↑ ← item.tool.itemDescriptors[J].textText↑; item.tool.itemDescriptors[J+1].zeroValTextText↑ ← item.tool.itemDescriptors[J].zeroValTextText↑; ENDLOOP; item.tool.nActiveItems↑ ← item.tool.nActiveItems↑ + 1; item.active ← TRUE; item.mode ← showText; item.justification ← right; item.idText↑ ← " "; item.textText↑ ← " "; item.zeroValTextText↑ ← " "; ShowItemMode[item]; ShowItemJustification[item]; END; DeleteItem: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; itemJ: CARDINAL ← item.j; IF NOT item.active THEN RETURN; FOR J: CARDINAL IN [itemJ..item.tool.nActiveItems↑) DO item.tool.itemDescriptors[J].mode ← item.tool.itemDescriptors[J+1].mode; item.tool.itemDescriptors[J].modeText↑ ← item.tool.itemDescriptors[J+1].modeText↑; item.tool.itemDescriptors[J].justification ← item.tool.itemDescriptors[J+1].justification; item.tool.itemDescriptors[J].justificationText↑ ← item.tool.itemDescriptors[J+1].justificationText↑; item.tool.itemDescriptors[J].idText↑ ← item.tool.itemDescriptors[J+1].idText↑; item.tool.itemDescriptors[J].textText↑ ← item.tool.itemDescriptors[J+1].textText↑; item.tool.itemDescriptors[J].zeroValTextText↑ ← item.tool.itemDescriptors[J+1].zeroValTextText↑; ENDLOOP; NilAnItem[item.tool.itemDescriptors[item.tool.nActiveItems↑]]; item.tool.nActiveItems↑ ← item.tool.nActiveItems↑-1; END; StepItemMode: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; IF NOT item.active THEN RETURN; item.mode ← SELECT item.mode FROM showText => showId, showId => showExp, showExp => showValue, showValue => noShow, noShow => showText, ENDCASE => ERROR; ShowItemMode[item]; END; ShowItemMode: PROCEDURE[item: ItemDisplay] = BEGIN IF NOT item.active THEN RETURN; item.modeText↑ ← SELECT item.mode FROM showText => "showText", showId => "showId", showExp => "showExp", showValue => "showValue", noShow => "noShow", ENDCASE => ERROR; END; StepItemJustification: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; IF NOT item.active THEN RETURN; item.justification ← SELECT item.justification FROM left => leftDecimal, leftDecimal => centered, centered => rightDecimal, rightDecimal => right, right => left, ENDCASE => ERROR; ShowItemJustification[item]; END; ShowItemJustification: PROCEDURE[item: ItemDisplay] = BEGIN IF NOT item.active THEN RETURN; item.justificationText↑ ← SELECT item.justification FROM left => "left", leftDecimal => "leftDecimal", centered => "centered", rightDecimal => "rightDecimal", right => "right", ENDCASE => ERROR; END; StepItemRowSumMode: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; IF NOT item.active THEN RETURN; item.rowSumMode ← SELECT item.rowSumMode FROM addVal => subVal, subVal => setZero, setZero => noEffect, noEffect => addVal, ENDCASE => ERROR; ShowItemRowSumMode[item]; END; ShowItemRowSumMode: PROCEDURE[item: ItemDisplay] = BEGIN IF NOT item.active THEN RETURN; item.rowSumModeText↑ ← SELECT item.rowSumMode FROM addVal => "addVal", subVal => "subVal", setZero => "setZero", noEffect => "noEffect", ENDCASE => ERROR; END; StepItemColSumMode: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; IF NOT item.active THEN RETURN; item.colSumMode ← SELECT item.colSumMode FROM addVal => subVal, subVal => setZero, setZero => noEffect, noEffect => addVal, ENDCASE => ERROR; ShowItemColSumMode[item]; END; ShowItemColSumMode: PROCEDURE[item: ItemDisplay] = BEGIN IF NOT item.active THEN RETURN; item.colSumModeText↑ ← SELECT item.colSumMode FROM addVal => "addVal", subVal => "subVal", setZero => "setZero", noEffect => "noEffect", ENDCASE => ERROR; END; StepItemValueMode: ENTRY PROCEDURE[data: REF ANY] = BEGIN item: ItemDisplay ← NARROW[data]; IF NOT item.active THEN RETURN; item.valueMode ← SELECT item.valueMode FROM rowSum => colSum, colSum => expression, expression => rowSum, ENDCASE => ERROR; ShowItemValueMode[item]; END; ShowItemValueMode: PROCEDURE[item: ItemDisplay] = BEGIN IF NOT item.active THEN RETURN; item.valueModeText↑ ← SELECT item.valueMode FROM rowSum => "rowSum", colSum => "colSum", expression => "expression", ENDCASE => ERROR; END; NilAnItem: PROCEDURE[item: ItemDisplay] = BEGIN item.active ← FALSE; item.modeText↑ ← " "; item.justificationText↑ ← " "; item.idText↑ ← " "; item.textText↑ ← " "; item.zeroValTextText↑ ← " "; END; -- main code TestGCellTool: Commander.CommandProc = TRUSTED {MakeAGCellToolInstance[NIL]}; Commander.Register[key: "TestGCellTool", proc: TestGCellTool, doc: ""]; END.. -- October 5, 1982 5:35 pm: Sturgis, started GCellToolImpl.mesa -- RTE: October 6, 1982 4:08 pm: used same nil rope ref for all rope refs. -- RTE: October 6, 1982 4:29 pm: display had bad shape, not enough room for needed text, so changed form. -- RTE: October 6, 1982 4:34 pm: now there is not text to edit in the text fileds, so replace initial NIL rope with non null rope. remark: October 6, 1982 4:39 pm: well, it displays, and one can change the entries, but BOY, is it not esthetic. Also it has some techinical problems in the way it deals with commands delivered beyond the active area. BUT, I will live with it. -- RTEs (3): October 7, 1982 2:47 pm: main commands appeared in each item, sending a cell sent only the first item, and nilanitem always nilled the item following the last active item, rather than the parameter item. -- RTE: October 8, 1982 3:23 pm: add code to catch a syntax error before text is sent to a cell. A syntax error in the cell for an an item which is not displayed leads to a mesa ERROR. -- RTE: October 8, 1982 4:45 pm: do not check for syntax error on showText mode items. -- change: October 11, 1982 3:18 pm: SetAGCellProc changed slightly. -- change: October 14, 1982 5:15 pm: GetSelection had changed slightly. -- change: October 16, 1982 3:42 pm: make into a monitor, set "entry" TRUE on calls to Get and Set GCellContents. -- RTE: October 21, 1982 2:45 pm: too many procs set as entry. -- RTE: October 21, 1982 2:53 pm: in getacell and setacell, test for tool.global = NIL is unjustified. -- October 22, 1982 1:42 pm: add rowSumMode, colSumMode, valueMode. -- RTE: October 23, 1982 12:18 pm: did not correctly label noew mode fields. -- RTE: October 23, 1982 3:43 pm: it is now ok to permit some identifiers which are NIL, or length 0, or a single blank. -- change: November 14, 1982 1:59 pm: convert to new selection logic. -- change: November 14, 1982 2:52 pm: add setZero to row and col sum modes. -- February 27, 1983 3:57 pm: replace display node, logical node etc with structurenode. In particular, GCell.GCell is replaced with StructureNode. Took about 5 minutes. -- change: June 22, 1984 4:28:33 pm PDT: convert to 5.2