NodeStyleTabsImpl.mesa
Written by Bill Paxton, December 1981
Last changed by Bill Paxton, June 7, 1983 2:52 pm
Last Edited by: Maxwell, January 6, 1983 10:15 am
Last Edited by: Plass, April 12, 1983 2:42 pm
Implements JaM commands for tab specifications
DIRECTORY
NodeStyle,
NodeStyleExtra,
NodeStyleObject,
TiogaLooks,
NameSymbolTable,
Real,
Rope,
JaMOps,
JaMBasic;
NodeStyleTabsImpl: CEDAR PROGRAM
IMPORTS JaMOps, NodeStyle, NodeStyleExtra, NodeStyleObject, Real, Rope
EXPORTS NodeStyle, NodeStyleExtra =
BEGIN OPEN R:Real, NodeStyle, NodeStyleExtra, NodeStyleObject;
Rules tabs procs
RulesTabCount: PUBLIC PROC [stop: RulesTabStop] RETURNS [count: INTEGER] = {
RETURN [stop.array.length/2] };
RulesTabInfo: PUBLIC PROC [stop: RulesTabStop, num: INTEGER]
RETURNS [weight, vshift: REAL] = TRUSTED {
For num in [0..RulesTabCount), returns the weight and vshift values for that rule.
ObjectToReal: PROC [ob: JaMBasic.Object] RETURNS [Real] = TRUSTED {
WITH ob:ob SELECT FROM
integer => RETURN[ob.ivalue];
real => RETURN[ob.rvalue];
ENDCASE => ERROR };
weight ← ObjectToReal[JaMOps.AGet[stop.array, num*2]];
vshift ← ObjectToReal[JaMOps.AGet[stop.array, num*2+1]] };
RulesTabInfoI: PUBLIC PROC [stop: RulesTabStop, num: INTEGER]
RETURNS [weight, vshift: INTEGER] = TRUSTED {
ObjectToInteger: PROC [ob: JaMBasic.Object] RETURNS [INTEGER] = TRUSTED {
WITH ob:ob SELECT FROM
integer => RETURN[ob.ivalue];
real => RETURN[R.RoundI[ob.rvalue]];
ENDCASE => ERROR };
weight ← ObjectToInteger[JaMOps.AGet[stop.array, num*2]];
vshift ← ObjectToInteger[JaMOps.AGet[stop.array, num*2+1]] };
Real table overflow for tab reals
GetTabRealCode: PROC [ref: Ref, stop: TabStop, which: TabRealParam, value: Real]
RETURNS [code: RealCode] = {
code ← EnterReal[value ! realTableOverflow => {
code ← overflow;
ref.dataList ← NEW[DataEntry ← [
ref.dataList, tab[stop, which, value, IntegerValue[value]]]];
CONTINUE }] };
GetTabOverflow: PUBLIC PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: Real] = {
FOR x: DataList ← ref.dataList, x.next UNTIL x=NIL DO
xx: REF DataEntry.tab = NARROW[x];
IF xx.tabStop=stop AND xx.which=which THEN RETURN [xx.value];
ENDLOOP;
ERROR -- failed to find it on the data list -- };
GetTabIntOverflow: PUBLIC PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: INTEGER] = {
FOR x: DataList ← ref.dataList, x.next UNTIL x=NIL DO
xx: REF DataEntry.tab = NARROW[x];
IF xx.tabStop=stop AND xx.which=which THEN RETURN [xx.valueI];
ENDLOOP;
ERROR -- failed to find it on the data list -- };
Miscellaneous commands
RelativeTabStopsOp: PUBLIC PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN {
PushText[frame,"illegal value for tabStops: should be fixed or relative"];
StyleError[frame,1] };
SELECT name FROM
fixed => ref.fixedTabs ← TRUE;
relative => ref.fixedTabs ← FALSE;
ENDCASE => { -- restore name to stack and return default
PushName[frame, name];
PushText[frame,"illegal value for tabStops: should be fixed or relative"];
StyleError[frame,2] }};
DefaultTabStopsOp: PUBLIC PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
tabStop: TabStop ← TabSpec[ref, frame];
tabStop.loc ← GetTabRealCode[ref, tabStop, loc, PopReal[frame]];
ref.defaultTabStops ← tabStop };
Parsing tab specs
TabStopOp: PUBLIC PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
tabStop: TabStop ← TabSpec[ref, frame];
loc: Real;
tabStop.loc ← GetTabRealCode[ref, tabStop, loc, PopReal[frame]];
Insert in list of tab stops. kept sorted by decreasing location, i.e., from right to left on page
this may result in a slight decrease in efficiency for the formatters, but it substantially reduces allocations during the creation of the list since styles tend to define tab stops in increasing order, so can add to start of list and list additions must be non-destructive of the previous list
loc ← GetTabLoc[tabStop, ref];
ref.numTabStops ← ref.numTabStops+1;
IF ref.tabStops = NIL OR GetTabLoc[ref.tabStops.first, ref] <= loc THEN
ref.tabStops ← CONS[tabStop, ref.tabStops]
ELSE { -- copy list up to first with smaller loc
old: LIST OF TabStop ← ref.tabStops;
new: LIST OF TabStop ← CONS[old.first, NIL];
ref.tabStops ← new;
FOR lst: LIST OF TabStop ← old.rest, lst.rest DO
IF lst=NIL OR GetTabLoc[lst.first, ref] <= loc THEN { -- insert here
new.rest ← CONS[tabStop, lst]; EXIT };
new.rest ← CONS[lst.first, NIL];
new ← new.rest;
ENDLOOP }};
TabSpec: PROC [ref: Ref, frame: Frame] RETURNS [tabStop: TabStop] = { -- parse tab specs
looks: TiogaLooks.Looks ← TabLooksSpec[frame];
breakIfPast: BOOL ← TabPastSpec[frame];
tabStop ← TabPattern[ref, frame];
tabStop.looks ← looks;
tabStop.breakIfPast ← breakIfPast;
TabAlign[tabStop, frame] };
TabLooksSpec: PROC [frame: Frame] RETURNS [lks: TiogaLooks.Looks] = TRUSTED {
name: Name;
ok: BOOLEAN;
SetLookBit: PROC [look: CHAR] RETURNS [quit: BOOL] = TRUSTED {
look ← Rope.Lower[look];
IF look IN ['a..'z] THEN lks[look] ← TRUE;
RETURN [FALSE] };
lks ← TiogaLooks.noLooks;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN RETURN;
IF name # looks THEN { PushName[frame, name]; RETURN };
JaMOps.StringForAll[JaMOps.PopString[frame.opstk], SetLookBit];
};
TabPastSpec: PROC [frame: Frame] RETURNS [break: BOOL] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN RETURN;
SELECT name FROM
breakIfPast => break ← TRUE;
spaceIfPast => break ← FALSE;
ENDCASE => { -- restore name to stack and return default
PushName[frame, name];
break ← FALSE }};
TabPattern: PROC [ref: Ref, frame: Frame] RETURNS [tabStop: TabStop] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN { tabStop ← NEW[blank TabStopRec]; RETURN };
SELECT name FROM
blank => tabStop ← NEW[blank TabStopRec];
leaders => {
leaderChar: BOOLFALSE;
string: string JaMBasic.Object;
value: Real;
SetLeaderChar: PROC [c: CHAR] RETURNS [quit: BOOL] = {
IF leaderChar THEN {
PushText[frame,"Cannot specify more than one character for tab leaders"];
StyleError[frame,1] };
leaderChar ← TRUE;
ldrStop.char ← c };
ldrStop: LeaderTabStop ← NEW[leaders TabStopRec];
tabStop ← ldrStop;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN ldrStop.congruent ← TRUE
ELSE SELECT name FROM
centered => ldrStop.congruent ← FALSE;
congruent => ldrStop.congruent ← TRUE;
ENDCASE => {
PushName[frame,name];
PushText[frame,"is not legal as value for tab leaders: congruent or centered"];
StyleError[frame,2] };
[value, ok] ← TryToPopReal[frame];
ldrStop.spacing ← GetTabRealCode[ref, tabStop, spacing, IF ok THEN value ELSE 0.0];
[string, ok] ← TryToPopString[frame];
IF ok THEN TRUSTED {JaMOps.StringForAll[string, SetLeaderChar]}
ELSE {
PushText[frame,"Must specify character for leaders"];
StyleError[frame,1] }};
rule => {
ruleStop: RuleTabStop ← NEW[rule TabStopRec];
tabStop ← ruleStop;
ruleStop.vshift ← GetTabRealCode[ref, tabStop, vshift, PopReal[frame]];
ruleStop.weight ← GetTabRealCode[ref, tabStop, weight, PopReal[frame]] };
rules => {
rulesStop: RulesTabStop ← NEW[rules TabStopRec];
tabStop ← rulesStop;
TRUSTED {rulesStop.array ← JaMOps.PopArray[frame.opstk] }};
ENDCASE => { -- restore name to stack and return default
PushName[frame, name];
tabStop ← NEW[blank TabStopRec] }};
MissingChar: PROC [frame: Frame] = {
PushText[frame,"Cannot specify more than one character for tab alignment"];
StyleError[frame,1] };
TabAlign: PROC [tabStop: TabStop, frame: Frame] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN { tabStop.alignment ← FlushLeft; RETURN };
SELECT name FROM
flushLeft => tabStop.alignment ← FlushLeft;
flushRight => tabStop.alignment ← FlushRight;
centered => tabStop.alignment ← Centered;
aligned => {
alignmentChar: BOOLFALSE;
string: string JaMBasic.Object;
SetAlignmentChar: PROC [c: CHAR] RETURNS [quit: BOOL] = {
IF alignmentChar THEN {
PushText[frame,"Cannot specify more than one character for tab alignment"];
StyleError[frame,1] };
alignmentChar ← TRUE;
tabStop.alignmentChar ← c };
tabStop.alignment ← Character;
[string, ok] ← TryToPopString[frame];
IF ok THEN TRUSTED {JaMOps.StringForAll[string, SetAlignmentChar]}
ELSE {
PushText[frame,"Must specify character for tab alignment"];
StyleError[frame,1] }};
ENDCASE => {
PushName[frame, name];
tabStop.alignment ← FlushLeft }};
END...