DIRECTORY List, TableBase, TableConstraints, TableLayout, TextNode, TSArtwork, TSFont, TSGlue, TSGraphic, TSObject, TSOps, TSOutput, TSTranslate, TSTypes; TableLayoutImpl: CEDAR PROGRAM IMPORTS List, TableBase, TableConstraints, TSFont, TSGlue, TSObject, TSOps, TSOutput, TSTranslate, TSTypes EXPORTS TableLayout = { OPEN TableBase, TableLayout; LayoutTable: PUBLIC PROCEDURE [table: RefTable, maxX, maxY, suggestedX, suggestedY: TSTypes.Dimn _ TSTypes.nilDimn] RETURNS [extent: TSTypes.Dimensions] = { IF table.branch = NIL OR table.tableGrid = NIL THEN ERROR ImplementationError["Malformed table does not have proper data structure"]; TableConstraints.SolveConstraints[table]; extent _ [TSTypes.zeroDimn, table.colGridPositions.grid[table.columnGrids], table.rowGridPositions.grid[FIRST[TableBase.GridNumber]], TSTypes.zeroDimn]; }; PaintTable: PUBLIC PROCEDURE [table: RefTable, handle: TSOutput.Handle, originX, originY: TSTypes.Dimn, extent: TSTypes.Dimensions] = { PaintTableBox: EnumeratedEntryProc = { WITH entry SELECT FROM box: RefTableBox => { IF box.tsObject # NIL THEN box.tsObject.paintProc[box.tsObject, handle, originX.AddDimn[box.x], originY.AddDimn[box.y], box.nodeExtents]; }; rule: RefTableRule => { thickness: TSTypes.Dimn; length: TSTypes.Dimn; x,y: TSTypes.Dimn; SELECT rule.orientation FROM horizontal => { thickness _ rule.thickness; length _ table.colGridPositions[rule.right].SubDimn[table.colGridPositions[rule.left]].AddDimn[rule.thickness]; }; vertical => { thickness _ table.rowGridPositions[rule.top].SubDimn[table.rowGridPositions[rule.bottom]].AddDimn[rule.thickness]; length _ rule.thickness; }; ENDCASE => ERROR; x _ table.colGridPositions[rule.left].SubDimn[rule.thickness.DivDimn[2]]; y _ table.rowGridPositions[rule.bottom].SubDimn[rule.thickness.DivDimn[2]]; handle.ruleProc[self~handle, leftX~originX.AddDimn[x], bottomY~originY.AddDimn[y], width~length, height~thickness]; }; background: RefTableBackground => NULL; -- there shouldn't be any of these, but ... ENDCASE => ERROR; }; IF table.branch = NIL OR table.tableGrid = NIL THEN ERROR ImplementationError["Malformed table does not have proper data structure"]; IF table.backgrounds # NIL THEN { FOR b: LIST OF RefTableBackground _ table.backgrounds, b.rest WHILE b # NIL DO background: RefTableBackground _ b.first; length: TSTypes.Dimn ~ table.colGridPositions[background.right].SubDimn[table.colGridPositions[background.left]]; thickness: TSTypes.Dimn ~ table.rowGridPositions[background.top].SubDimn[table.rowGridPositions[background.bottom]]; x: TSTypes.Dimn ~ table.colGridPositions[background.left]; y: TSTypes.Dimn ~ table.rowGridPositions[background.bottom]; handle.colorProc[ self~handle, hue~background.hue, saturation~background.saturation, brightness~background.brightness]; -- grey handle.ruleProc[self~handle, leftX~originX.AddDimn[x], bottomY~originY.AddDimn[y], width~length, height~thickness]; handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black ENDLOOP; }; IF table.gridOverlayThickness # TSTypes.nilDimn THEN { halfThickness: TSTypes.Dimn ~ table.gridOverlayThickness.DivDimn[2]; FOR i: TableBase.GridNumber IN [0..table.rowGrids] DO handle.colorProc[ self~handle, hue~table.gridOverlayHue, saturation~table.gridOverlaySaturation, brightness~table.gridOverlayBrightness]; -- grey handle.ruleProc[ self~handle, leftX~originX.SubDimn[halfThickness], bottomY~originY.AddDimn[table.rowGridPositions.grid[i]].SubDimn[halfThickness], width~extent[right].AddDimn[table.gridOverlayThickness], height~table.gridOverlayThickness]; handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black ENDLOOP; FOR i: TableBase.GridNumber IN [0..table.columnGrids] DO handle.colorProc[ self~handle, hue~table.gridOverlayHue, saturation~table.gridOverlaySaturation, brightness~table.gridOverlayBrightness]; -- grey handle.ruleProc[ self~handle, leftX~originX.AddDimn[table.colGridPositions.grid[i]].SubDimn[halfThickness], bottomY~originY.SubDimn[halfThickness], width~table.gridOverlayThickness, height~extent[up].AddDimn[table.gridOverlayThickness]]; handle.colorProc[self~handle, hue~0.0, saturation~0.0, brightness~0.0]; -- black ENDLOOP; }; EnumerateByRows[table, PaintTableBox]; }; AlignExtents: PUBLIC PROCEDURE [table: TableBase.RefTable, box: TableBase.RefTableBox] RETURNS [extents: TSTypes.Dimensions] ~ TRUSTED { IF box.nodeExtentsValid THEN RETURN [box.boxExtents] ELSE { bearoffExtents: TSTypes.Dimensions ~ BearoffExtents[table, box]; MakeExtentsValid[box]; SELECT box.rowAlignment FROM flushTop => { extents[up] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]]; extents[down] _ TSTypes.zeroDimn; }; flushBottom => { extents[up] _ TSTypes.zeroDimn; extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]]; }; center => { extents[up] _ extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]].DivDimn[2]; }; topBaseline => { baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box]; baseline: BaselineListRec _ baselineList.first^; extents[up] _ baseline.y; extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y]; }; bottomBaseline => { baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box]; baseline: BaselineListRec _ NthElement[baselineList, -1]^; extents[up] _ baseline.y; extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y]; }; centerOnTopBaseline => { baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box]; numberOfBaselines: INT ~ Length[baselineList]; baseline: BaselineListRec _ NthElement[baselineList, (numberOfBaselines+1)/2]^; extents[up] _ baseline.y; extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y]; }; centerOnBottomBaseline => { baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box]; numberOfBaselines: INT ~ Length[baselineList]; baseline: BaselineListRec _ NthElement[baselineList, (numberOfBaselines/2)+1]^; extents[up] _ baseline.y; extents[down] _ box.nodeExtents[up].AddDimn[box.nodeExtents[down]].SubDimn[baseline.y]; }; ENDCASE => ERROR UnimplementedCase; IF box.alignOnChar THEN { baselineList: LIST OF BaselineList ~ BaselineListFromTableBox[box]; baseline: BaselineListRec _ IF box.alignFirst THEN baselineList.first^ ELSE NthElement[baselineList, -1]^; extents[left] _ baseline.x; extents[right] _ box.nodeExtents[left].AddDimn[box.nodeExtents[right]].SubDimn[baseline.x]; } ELSE { SELECT box.colAlignment FROM flushLeft => { extents[left] _ TSTypes.zeroDimn; extents[right] _ box.nodeExtents[left].AddDimn[box.nodeExtents[right]]; }; flushRight => { extents[left] _ box.nodeExtents[left].AddDimn[box.nodeExtents[right]]; extents[right] _ TSTypes.zeroDimn; }; center => extents[left] _ extents[right] _ box.nodeExtents[left].AddDimn[box.nodeExtents[right]].DivDimn[2]; ENDCASE => ERROR UnimplementedCase; }; box.xOffset _ extents[right].SubDimn[box.nodeExtents[right]]; box.yOffset _ extents[down].SubDimn[box.nodeExtents[down]]; extents[left] _ extents[left].AddDimn[bearoffExtents[left]]; extents[right] _ extents[right].AddDimn[bearoffExtents[right]]; extents[up] _ extents[up].AddDimn[bearoffExtents[up]]; extents[down] _ extents[down].AddDimn[bearoffExtents[down]]; box.boxExtents _ extents; box.nodeExtentsValid _ TRUE; }; }; BearoffExtents: PROCEDURE [table: TableBase.RefTable, box: TableBase.RefTableBox] RETURNS [extents: TSTypes.Dimensions] ~ { extents _ box.bearoffExtents; IF extents[left] = TSTypes.nilDimn THEN extents[left] _ table.bearoffExtents[left]; IF extents[right] = TSTypes.nilDimn THEN extents[right] _ table.bearoffExtents[right]; IF extents[up] = TSTypes.nilDimn THEN extents[up] _ table.bearoffExtents[up]; IF extents[down] = TSTypes.nilDimn THEN extents[down] _ table.bearoffExtents[down]; }; MakeExtentsValid: PROC [box: TableBase.RefTableBox] ~ { IF NOT box.nodeExtentsValid THEN { box.tsObject _ CreateTypesetObject[box.node]; box.nodeExtents _ box.tsObject.layoutProc[box.tsObject]; box.nodeExtentsValid _ TRUE; }; }; BaselineList: TYPE ~ REF BaselineListRec; BaselineListRec: TYPE ~ RECORD [ x, y: TSTypes.Dimn, extent: TSTypes.Dimensions]; Reverse: PROC [list: LIST OF BaselineList] RETURNS [LIST OF BaselineList] ~ TRUSTED { RETURN [LOOPHOLE[List.Reverse[LOOPHOLE[list]], LIST OF BaselineList]]; }; Length: PROC [list: LIST OF BaselineList] RETURNS [INT] ~ TRUSTED { RETURN [List.Length[LOOPHOLE[list]]]; }; NthElement: PROC [list: LIST OF BaselineList, n: INT] RETURNS [BaselineList] ~ TRUSTED { RETURN [LOOPHOLE[List.NthElement[LOOPHOLE[list], n], BaselineList]]; }; BaselineListFromTableBox: PROCEDURE [box: TableBase.RefTableBox] RETURNS [baselineList: LIST OF BaselineList] ~ TRUSTED { BaselinesFromDownList: PROCEDURE [tsBox: TSObject.Box] RETURNS [baselineList: LIST OF BaselineList] ~ TRUSTED { WITH b: tsBox SELECT FROM list => { source: TSObject.ListReader ~ b.items.CreateReader[]; x: TSTypes.Dimn _ TSTypes.zeroDimn; y: TSTypes.Dimn _ TSTypes.zeroDimn; UNTIL source.End[] DO SELECT source.CurrentTag[] FROM exception => { item: REF ANY _ source.CurrentItem[]; SELECT TRUE FROM ISTYPE[item, TSObject.Box] => { tsBox: TSObject.Box ~ NARROW[item]; WITH b: tsBox SELECT FROM list => { baseline: BaselineListRec _ BaselineFromRightList[tsBox]; baseline.y _ baseline.y.AddDimn[y]; y _ y.AddDimn[baseline.extent[up]].AddDimn[baseline.extent[down]]; baselineList _ CONS[NEW[BaselineListRec _ baseline], baselineList]; }; ENDCASE => ERROR; }; ISTYPE[item, TSObject.Glue] => { glue: TSObject.Glue ~ NARROW[item]; delta: TSTypes.Dimn ~ TSGlue.FixGlue[glue^, b.glueset]; y _ y.AddDimn[delta]; }; ISTYPE[item, TSObject.Kern] => { kern: TSObject.Kern ~ NARROW[item]; y _ y.AddDimn[kern^]; }; ENDCASE => ERROR; }; ENDCASE => ERROR; source.Next[]; ENDLOOP; }; ENDCASE => ERROR ImplementationError["inside BaselinesFromDownList with a nonlist box"]; IF baselineList # NIL THEN baselineList _ Reverse[baselineList]; }; BaselineFromRightList: PROCEDURE [tsBox: TSObject.Box] RETURNS [BaselineListRec] ~ TRUSTED { WITH b: tsBox SELECT FROM list => { x: TSTypes.Dimn _ TSTypes.zeroDimn; y: TSTypes.Dimn _ TSTypes.zeroDimn; x _ x.AddDimn[b.extent[left]]; y _ y.AddDimn[b.extent[up]]; IF box.alignOnChar THEN x _ x.AddDimn[PositionOfAlignChar[box.alignChar, box.alignFirst, b.items.CreateReader[], b.glueset]]; RETURN [[x, y, b.extent]]; }; ENDCASE => ERROR ImplementationError["inside BaselineFromRightList with a nonlist box"]; }; tsBox: TSObject.Box; IF NOT box.nodeExtentsValid THEN MakeExtentsValid[box]; tsBox _ BoxFromTypesetObject[box.tsObject]; WITH b: tsBox SELECT FROM list => { SELECT b.direction FROM down => baselineList _ BaselinesFromDownList[tsBox]; right => baselineList _ LIST[NEW[BaselineListRec _ BaselineFromRightList[tsBox]]]; ENDCASE => ERROR UnimplementedCase; }; ENDCASE => ERROR ImplementationError["Expecting a down list box from a TypsetObject"]; }; PositionOfAlignChar: PROC [alignChar: CHAR, alignFirst: BOOLEAN, boxList: TSObject.ListReader, glueSet: TSGlue.GlueSet] RETURNS [alignX: TSTypes.Dimn] ~ { direction: TSObject.Direction ~ right; opposite: TSObject.Direction ~ left; x: TSTypes.Dimn _ TSTypes.zeroDimn; lastCharX: TSTypes.Dimn _ TSTypes.zeroDimn; UNTIL boxList.End[] DO SELECT boxList.CurrentTag[] FROM char => { thisChar: CHAR ~ boxList.CurrentChar[]; extent: TSTypes.Dimensions _ boxList.currentFont.CharDimensions[thisChar]; IF alignChar = thisChar THEN { IF alignFirst THEN RETURN [lastCharX]; }; lastCharX _ x _ x.AddDimn[extent[direction].SubDimn[extent[opposite]]]; boxList.Next[]; }; space => { WHILE boxList.CurrentTag[] = space DO x _ x.AddDimn[TSGlue.FixGlue[boxList.currentFont.SpaceGlue[], glueSet]]; boxList.Next[]; ENDLOOP; }; exception => { item: REF ANY _ boxList.CurrentItem[]; SELECT TRUE FROM ISTYPE[item, TSObject.Glue] => { g: TSObject.Glue _ NARROW[item]; x _ x.AddDimn[TSGlue.FixGlue[g^, glueSet]]; boxList.Next[]; }; ISTYPE[item, TSObject.Kern] => { x _ x.AddDimn[NARROW[item, TSObject.Kern]^]; boxList.Next[]; }; ENDCASE => ERROR UnimplementedCase; }; ENDCASE => ERROR UnimplementedCase; ENDLOOP; RETURN [lastCharX]; }; CreateTypesetObject: TSArtwork.ObjectFromBranchProc = { object _ NEW[TSGraphic.ObjectRec]; object.paintProc _ TypesetObjectPaint; object.layoutProc _ TypesetObjectLayout; object.data _ NEW[TypesetObjectRec _ [node: node]]; }; TypesetObjectRec: TYPE = RECORD [ node: TextNode.Ref, vlist: TSObject.ItemList, box: TSObject.Box ]; TypesetObjectLayout: TSGraphic.LayoutProc = TRUSTED { data: REF TypesetObjectRec _ NARROW[self.data]; data.vlist _ TSTranslate.TreeToVlist[data.node].galley; data.box _ TSOps.GetSlimBoxFrom[data.vlist]; extent _ data.box.extent; }; TypesetObjectPaint: TSGraphic.PaintProc = { data: REF TypesetObjectRec _ NARROW[self.data]; TSOutput.BoxOut[NARROW[context], originX, originY, data.box^]; }; BoxFromTypesetObject: PROC [self: TSGraphic.Object] RETURNS [box: TSObject.Box] ~ { data: REF TypesetObjectRec _ NARROW[self.data]; box _ data.box; }; }. ΌTableLayoutImpl.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Rick Beach, February 18, 1985 10:07:47 pm PST paint the table to an output sink handle positioned with bottom left corner at (originX, originY) to fit the given extent. paint the table box with top left corner (box.x, box.y) relative to (originX, originY) Put out some interesting grid lines Should check table.rows and table.cols for those specifications Κ D˜™Jšœ Οmœ1™J˜—šŸœžœžœ˜SJšœžœžœ ˜/J˜J˜—J˜—…—2¦@¦