GraphUpdate.mesa, Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, November 21, 1985 9:48:30 pm PST
DIRECTORY
Convert USING [RopeFromInt],
Graph USING [CaretIndex, ColorIndex, Entity, EntityGroupList, EntityHashSize, EntityRec, EntityGroup, EntityGroupRec, EntityList, FontIndex, GraphHandle, HashIndex, NestedEntitiesRec, NumberOfColors, NumberOfFonts, PaintAction, ROPE, Text, TextRec, Texts, UnitLineWidth, ValueList, Viewer, XY],
GraphCarets USING [Move, TurnOff, TurnOn],
GraphConvert USING [RopeOfSlope, VLFromSDL, VLsFromValues],
GraphCleanUp USING [CleanUpVL],
GraphPrivate USING [AddEntityButton, AddGroupButton, AddTextButton, GraphAtomProc, PaintAll, PaintEntity, PaintGrids, PaintTarget, PaintText, UpdateEntityButton, UpdateTextButton, systemColor],
GraphUtil USING [Almost, AppendEGL, AppendEntityList, BlinkMsg, EntityFromId, GetIntField, GetRealField, InitSegAll, InitSegEnd, LengthOfVL, NewEntityId, NewGroupId, NewTextId, RaiseError, RealToScreenI, SetColor, SetIntField, SetSegments, TextFromId, UpdateSegAll, UpdateSegEnd],
Imager USING [Error],
ImagerFont USING [Find, Font, Scale],
IO USING [int, PutFR],
Rope USING [Cat, Concat],
VFonts USING [EstablishFont],
ViewerTools USING [GetContents, SetContents];
GraphUpdate: CEDAR PROGRAM
IMPORTS Convert, GraphCarets, GraphCleanUp, GraphConvert, GraphPrivate, GraphUtil, Imager, ImagerFont, IO, Rope, VFonts, ViewerTools
EXPORTS GraphPrivate = { OPEN Graph, GraphPrivate, GraphUtil;
Update: PUBLIC GraphAtomProc = {
If handle = nil or controller = nil then noop; otherwise:
updates internal values based on users input on panel and, if chart.viewer # nil, also updates display.
IF handle # NIL THEN IF handle.controller # NIL THEN { OPEN handle;
msg: ROPE; i: INT; -- r: REAL;
SELECT atom FROM
$Divisions => UpdateDivisions[handle];
$Bounds => UpdateBounds[handle];
$Carets => UpdateCarets[handle];
$Targets => UpdateTargets[handle];
$Grids => UpdateGrids[handle];
$Color => {
[msg, i] ← GetIntField[controller.colorIndex];
IF msg = NIL THEN
IF i IN ColorIndex THEN UpdateColor[handle, i]
ELSE BlinkMsg[Rope.Cat[
"Index must be in [0..", Convert.RopeFromInt[NumberOfColors], ")"]];
};
$Font => {
[msg, i]← GetIntField[controller.fontIndex];
IF msg = NIL THEN
IF i IN FontIndex THEN UpdateFont[handle, i]
ELSE BlinkMsg[Rope.Cat[
"Index must be in [0..", Convert.RopeFromInt[NumberOfFonts], ")"]];
};
$Text => {
[msg, i] ← GetIntField[controller.textId];
IF msg = NIL THEN {
text: Text ← TextFromId[handle.allTexts, i];
UpdateText[handle, text, i]; -- text = nil => add it.
};
};
$Entity, $EntityAndValues => {
[msg, i] ← GetIntField[controller.entityId];
IF msg = NIL THEN {
entity: Entity ← EntityFromId[entityHash[i MOD EntityHashSize], i];
UpdateEntity[handle, entity, i, atom = $EntityAndValues];
};
};
$XYValues => {
msg: ROPE; i: INT;
[msg, i] ← GetIntField[controller.idOfy];
IF msg = NIL THEN {
entity: Entity ← EntityFromId[entityHash[i MOD EntityHashSize], i];
IF entity = NIL THEN BlinkMsg["No curve with this id. To add an entity, please use the Curve entry on the Spec menu."]
ELSE UpdateXYValues[handle, entity];
};
};
$CurveGroup => {
[msg, i] ← GetIntField[controller.entityId];
IF msg = NIL THEN {
eg: EntityGroup ← EntityGroupFromId[handle.entityGroupList, i];
UpdateEntityGroup[handle, eg, i];
};
};
$Crosssection => {
[msg, r] ← GetRealField[controller.entityId];
IF msg = NIL THEN UpdateCrosssection[controller, x];
};
ENDCASE => RaiseError[$UnknownAtom, "in Update"];
};
}; -- Update
UpdateDivisions: PROC[handle: GraphHandle] = { OPEN handle;
graph.auto[divisions] ← controller.auto[divisions];
graph.division[x] ← UpdateFromIntField[controller.divX, graph.division[x]];
graph.division[y] ← UpdateFromIntField[controller.divY, graph.division[x]];
IF graph.division[x] < 1 OR graph.division[y] < 1 THEN BlinkMsg["x or y divisions < 1."]
ELSE IF chart.viewer # NIL THEN PaintAll[handle, TRUE]; -- paint everything.
}; -- SetDivisionFields
UpdateBounds: PROC[handle: GraphHandle] = { OPEN handle;
graph.auto[bounds] ← controller.auto[bounds];
graph.bounds ← [
xmin: UpdateFromRealField[controller.xmin, graph.bounds.xmin],
ymin: UpdateFromRealField[controller.ymin, graph.bounds.ymin],
xmax: UpdateFromRealField[controller.xmax, graph.bounds.xmax],
ymax: UpdateFromRealField[controller.ymax, graph.bounds.ymax]
];
IF NOT graph.auto[bounds] AND (graph.bounds.xmin >= graph.bounds.xmax OR graph.bounds.ymin >= graph.bounds.ymax) THEN BlinkMsg["Illegal bounds. (xmin >= xmax or ymin >= ymax.)"]
ELSE IF chart.viewer # NIL THEN PaintAll[handle, TRUE];
}; -- UpdateBounds
UpdateCarets: PROC[handle: GraphHandle] = { OPEN handle;
UpdateCaret: PROC[index: CaretIndex] = {
vx: Viewer ← controller.caretPlace[index][x];
vy: Viewer ← controller.caretPlace[index][y];
rx: REAL ← UpdateFromRealField[vx, graph.caret[index].place.x];
ry: REAL ← UpdateFromRealField[vy, graph.caret[index].place.y];
sx: INTEGER ← RealToScreenI[handle, rx, x];
sy: INTEGER ← RealToScreenI[handle, ry, y];
graph.caret[index]^ ← [on: controller.caretOn[index], place: [rx, ry]];
IF chart.viewer # NIL THEN {
GraphCarets.Move[handle, sx, sy, index];
IF graph.caret[index].on THEN GraphCarets.TurnOn[handle, index]
ELSE GraphCarets.TurnOff[handle, index];
no fields on panel have to do with blinking.
};
}; -- UpdateCaret
FOR i: CaretIndex IN CaretIndex DO UpdateCaret[primary] ENDLOOP;
ViewerTools.SetContents[controller.slope,
IF (graph.showSlope ← controller.slopeOn) THEN
GraphConvert.RopeOfSlope[graph.caret[primary].place, graph.caret[secondary].place]
ELSE NIL];
}; -- UpdateCarets
UpdateTargets: PROC[handle: GraphHandle] = { OPEN handle;
UpdateTarget: PROC[xy: XY] = {
IF chart.viewer # NIL AND graph.target[xy].on THEN PaintTarget[handle, erase, xy];
graph.target[xy].value ← UpdateFromRealField[
controller.targetValue[xy], graph.target[xy].value];
graph.target[xy].width ← UpdateFromRealField[
controller.targetWidth[xy], graph.target[xy].width];
graph.target[xy].colorIndex ← UpdateFromIntField[
controller.targetColor[xy], graph.target[xy].colorIndex];
IF graph.target[xy].colorIndex NOT IN ColorIndex THEN {
graph.target[xy].colorIndex ← 13;
BlinkMsg["Color index out of range. Default is used."];
};
IF (graph.target[xy].on ← controller.targetOn[xy]) THEN
IF chart.viewer # NIL THEN PaintTarget[handle, paint, xy];
};
UpdateTarget[x];
UpdateTarget[y];
}; -- UpdateTargets
UpdateGrids: PROC[handle: GraphHandle] = { OPEN handle;
UpdateGrid: PROC[wasOn, isOn: BOOL, xy: XY] = {
IF wasOn # isOn THEN {
IF chart.viewer # NIL THEN {
IF wasOn THEN PaintGrids[handle, erase, xy];
PaintGrids[handle, paint, xy]; -- paint grids or ticks.
};
graph.grids[xy] ← isOn;
};
};
UpdateGrid[graph.grids[x], controller.gridOn[x], x];
UpdateGrid[graph.grids[y], controller.gridOn[y], y];
}; -- UpdateGrids
UpdateColor: PROC[handle: GraphHandle, index: ColorIndex] = { OPEN handle;
GetRGB: PROC[v: Viewer, r: REAL] RETURNS [rgb: REAL] = {
rgb ← UpdateFromRealField[v, r];
IF rgb > 1.0 OR rgb < 0.0 THEN {
rgb ← MAX[0.0, MIN[1.0, rgb]];
BlinkMsg["color value limited by [0..1]."];
};
};
graph.color[index].R ← GetRGB[controller.red, graph.color[index].R];
graph.color[index].G ← GetRGB[controller.green, graph.color[index].G];
graph.color[index].B ← GetRGB[controller.blue, graph.color[index].B];
systemColor[index] ← SetColor[index, graph.color[index]];
}; -- UpdateColor
UpdateFont: PROC[handle: GraphHandle, index: FontIndex] = { OPEN handle;
PaintTextsOfThisFont: PROC [action: PaintAction] = {
IF chart.viewer # NIL THEN FOR ts: Texts ← graph.texts, ts.rest UNTIL ts = NIL DO
text: Text ← ts.first;
IF text.fontIndex = index THEN PaintText[handle, action, text];
ENDLOOP;
}; -- PaintTextsOfThisFont
msg: ROPE;
vFontSize: INT;
pFontScale: REAL;
vFont, pFont: ImagerFont.Font ← NIL;
fontFamily: ROPE ← ViewerTools.GetContents[controller.fontFamily];
IF fontFamily = NIL THEN {BlinkMsg["Specify font family."]; RETURN};
[msg, vFontSize] ← GetIntField[controller.vFontSize];
IF msg # NIL THEN RETURN;
[msg, pFontScale] ← GetRealField[controller.pFontScale];
IF msg # NIL THEN RETURN;
vFont ← VFonts.EstablishFont[fontFamily, vFontSize, controller.boldOn, controller.italicOn, TRUE]; -- true means default on failure.
pFont ← ImagerFont.Scale[
ImagerFont.Find[Rope.Cat[
"Xerox/PressFonts/",
fontFamily,
Rope.Concat[IF controller.boldOn THEN "-b" ELSE "-m",
IF controller.italicOn THEN "ir" ELSE "rr"]]],
pFontScale
! Imager.Error => {pFont ← NIL; CONTINUE}];
IF pFont = NIL THEN BlinkMsg["Can't find font."]
ELSE {
PaintTextsOfThisFont[erase];
graph.font[index] ← [fontFamily, controller.boldOn, controller.italicOn, vFontSize, pFontScale];
imagerFonts[screen][index] ← vFont;
imagerFonts[interpress][index] ← pFont;
PaintTextsOfThisFont[paint];
};
}; -- UpdateFont
UpdateText: PROC[handle: GraphHandle, text: Text, id: INT] = { OPEN handle;
rope: ROPE ← ViewerTools.GetContents[controller.textContent];
msg: ROPENIL;
add: BOOL ← text = NIL;
int: INT;
GetTextPlace: PROC [v: Viewer, original: REAL] RETURNS [r: REAL] = {
r ← UpdateFromRealField[v, original];
IF r > 3.0 OR r < - 3.0 THEN {
r ← MAX[-3.0, MIN[3.0, r]];
BlinkMsg["Text coordinates limited by [-3..3]"];
};
}; -- GetTextPlace
IF rope = NIL THEN {BlinkMsg["name field is empty."]; RETURN};
IF add THEN text ← NEW[TextRec ← []]
ELSE IF chart.viewer # NIL THEN PaintText[handle, erase, text];
int ← UpdateFromIntField[controller.textFont, text.fontIndex];
IF int NOT IN FontIndex THEN msg ← "Illegal font index."
ELSE text.fontIndex ← int;
int ← UpdateFromIntField[controller.textColor, text.colorIndex];
IF int NOT IN ColorIndex THEN msg ← msg.Cat[" Illegal color index."]
ELSE text.colorIndex ← int;
IF msg # NIL THEN {BlinkMsg[msg]; text ← NIL; RETURN};
text^ ← [
text: rope,
place: [GetTextPlace[controller.textPlaceX, text.place.x],
GetTextPlace[controller.textPlaceY, text.place.y]],
fontIndex: text.fontIndex,
colorIndex: text.colorIndex,
rotation: UpdateFromRealField[controller.textRotation, text.rotation],
justifX: controller.justifX,
justifY: controller.justifY,
id: IF add THEN NewTextId[handle, id] ELSE id
];
IF add THEN SetIntField[controller.textId, text.id];
IF chart.viewer # NIL THEN PaintText[handle, paint, text];
IF add THEN {
handle.allTexts ← CONS[text, handle.allTexts];
graph.texts ← CONS[text, graph.texts];
AddTextButton[handle, text];
}
ELSE UpdateTextButton[handle, text];
}; -- UpdateText
UpdateX: PROC [handle: GraphHandle] = { OPEN handle; -- proc no use for now.
length, pos: INT;
vList, last: ValueList;
[vList, last, length, pos] ← GraphConvert.ValueListFromRope[
ViewerTools.GetContents[controller.xValues]];
IF pos # 0 THEN RETURN;
IF vList = NIL THEN {BlinkMsg["The values field is empty."]; RETURN};
IF length # entityGroupList.first.length THEN {
BlinkMsg[Rope.Cat["There should be ",
Convert.RopeFromInt[entityGroupList.first.length],
"numbers in the values field."]];
RETURN};
UpdateSegEnd[entityGroupList.first.x, vList];
IF chart.viewer # NIL THEN PaintAll[handle];
}; -- UpdateX
UpdateEntity: PROC [handle: GraphHandle, entity: Entity, id: INT, valuesToo: BOOLFALSE] = { OPEN handle;
rules:
if entity # nil:
if not valuesToo, update all fields except the values.
if valuesToo, and if values don't have syntax errors, then update values too.
if x's and y's are "almost" the same as original values, don't change values.
if xs are "almost" the same as original values, but not ys, then update y values.
if ys are "almost" the same as original values, but not xs, then update x values.
if both xs and ys are different from the original values, but the length is not changed, then update both xs and ys.
if both xs and ys are different from the original values, and the length is changed, then error.
if entity = nil,
if not valuesToo, error.
if valuesToo, then if values don't have syntax errors, add the entity to a group of the same x (otherwise to a new group) and intialize its values.
msg: ROPENIL;
index: INT ← 0;
add: BOOL ← entity = NIL;
plotted: BOOLIF add THEN FALSE ELSE (EntityFromId[graph.entityList, entity.id] # NIL);
plotExits: BOOL ← chart.viewer # NIL;
vlx, vly, lastX, lastY: ValueList;
lenX, lenY: INT;
group: EntityGroup ← NIL;
vList: ValueList;
eGroup: EntityGroup;
[msg, groupId] ← GetIntField[controller.entityGroupId, "group id"];
IF msg # NIL THEN RETURN;
eGroup ← EntityGroupFromId[handle.entityGroupList, groupId];
IF eGroup = NIL THEN {
BlinkMsg[Rope.Cat["There is no group with id = ", Convert.RopeFromInt[groupId], "."]];
RETURN;
};
[vList, length, pos] ← GraphConvert.ValueListFromRope[
ViewerTools.GetContents[controller.entityValues]];
IF pos # 0 THEN RETURN;
IF vList = NIL THEN {BlinkMsg["Error in the values field."]; RETURN};
IF length # entityGroupList.first.length THEN {
BlinkMsg[Rope.Cat["There should be ",
Convert.RopeFromInt[entityGroupList.first.length],
"numbers in the values field."]];
RETURN};
some checking:
1. check color index
index ← UpdateFromIntField[controller.entityColor, IF add THEN 0 ELSE entity.colorIndex];
IF index NOT IN ColorIndex THEN {BlinkMsg[" Illegal color index."]; RETURN};
2. enforce adding entity thru spec menu
IF add AND NOT valuesToo THEN {
BlinkMsg["Click with ctrl-shift at the Curve entry, if you really want to add a new curve."];
RETURN;
};
3. check values
IF valuesToo THEN {
[vlx, vly, lastX, lastY, msg] ← GraphConvert.VLsFromValues[handle];
IF msg = NIL THEN {
lenX ← LengthOfVL[vlx];
lenY ← LengthOfVL[vly];
IF lenX # lenY THEN msg ← IO.PutFR[
"number of x values = %g, but number of y values = %g.",
IO.int[lenX], IO.int[lenY]]
ELSE IF NOT add THEN IF lenX # entity.group.length THEN
msg ← IO.PutFR[
"There should be %g values on this curve, but only %g are specified.",
IO.int[entity.group.length], IO.int[lenX]];
};
IF msg # NIL THEN {BlinkMsg[msg]; RETURN}
};
IF add THEN { -- allocate entity (and perhaps its group too).
iHash: HashIndex;
FOR egl: EntityGroupList ← entityGroupList, egl.rest UNTIL egl = NIL DO
eg: EntityGroup ← egl.first;
IF AlmostSameVL[vlx, IF eg.x.segments = NIL THEN eg.x.oldValues ELSE GraphConvert.VLFromSDL[eg.x.segments]] THEN {
group ← eg; EXIT};
ENDLOOP;
IF group = NIL THEN { -- create a new group, add it to entityGroupList, and init x fields.
group ← NEW[EntityGroupRec ← [
x: NEW[EntityRec ← [
name: "X",
oldValues: vlx,
lastValue: lastX,
id: NewEntityId[handle, 0]
]],
ys: NEW[NestedEntitiesRec ← []],
id: NewGroupId[handle, 0],
length: lenX
]];
group.x.group ← group; -- not for now.
group.x.parent ← group.ys; -- not for now.
group.ys.comment ← Convert.RopeFromInt[group.id];
entityGroupList ← AppendEGL[entityGroupList, CONS[group, NIL]];
InitSegEnd[group.x];
AddGroupButton[handle, group];
};
entity ← NEW[EntityRec ← [
name: ViewerTools.GetContents[controller.entityName],
comment: ViewerTools.GetContents[controller.entityCmt],
colorIndex: index,
mark: controller.mark,
width: UpdateFromRealField[controller.entityWidth, entity.width],
oldValues: vly,
group: group,
parent: group.ys,
id: NewEntityId[handle, id],
lastValue: lastY
]];
InitSegAll[entity];
graph.entityList ← AppendEntityList[graph.entityList, CONS[entity, NIL]];
group.ys.entityList ← AppendEntityList[group.ys.entityList, CONS[entity, NIL]];
iHash ← entity.id MOD EntityHashSize;
entityHash[iHash] ← CONS[entity, entityHash[iHash]];
SetIntField[controller.entityId, entity.id];
SetIntField[controller.idOfy, entity.id];
AddEntityButton[handle, entity];
PaintEntity[handle, paint, entity, TRUE];
}
ELSE { -- not adding a new entity
sameX, sameY: BOOL;
IF plotExits AND plotted THEN PaintEntity[handle, erase, entity, TRUE];
entity^ ← [
name: ViewerTools.GetContents[controller.entityName],
comment: ViewerTools.GetContents[controller.entityCmt],
colorIndex: index,
mark: controller.mark,
width: UpdateFromRealField[controller.entityWidth, entity.width],
oldValues: entity.oldValues,
group: entity.group,
parent: entity.parent,
segments: entity.segments,
id: entity.id
];
UpdateEntityButton[handle, entity];
IF NOT plotted THEN {
IF entity.group.x.segments = NIL THEN InitSegEnd[entity.group.x];
InitSegAll[entity];
graph.entityList ← AppendEntityList[graph.entityList, CONS[entity, NIL]];
};
IF valuesToo THEN {
sameX ← AlmostSameVL[vlx, GraphConvert.VLFromSDL[entity.group.x.segments]];
sameY ← AlmostSameVL[vly, GraphConvert.VLFromSDL[entity.segments]];
}
ELSE sameX ← sameY ← TRUE;
IF sameX THEN {
IF NOT sameY THEN UpdateSegAll[entity, vly];
IF plotExits THEN PaintEntity[handle, paint, entity, TRUE];
}
ELSE { -- x changed, whether same y or not.
UpdateSegEnd[entity.group.x, vlx];
FOR el: EntityList ← handle.graph.entityList, el.rest UNTIL el = NIL DO
SetSegments[el.first];
ENDLOOP;
IF plotExits THEN PaintAll[handle];
};
};
IF valuesToo THEN {
vlx ← GraphCleanUp.CleanUpVL[vlx];
vly ← GraphCleanUp.CleanUpVL[vly];
lastX ← GraphCleanUp.CleanUpVL[lastX];
lastY ← GraphCleanUp.CleanUpVL[lastY];
};
}; -- UpdateEntity
UpdateXYValues: PROC [handle: GraphHandle, entity: Entity] = {
xvl, yvl, lastX, lastY: ValueList;
msg: ROPE;
[xvl, yvl, lastX, lastY, msg] ← GraphConvert.VLsFromValues[handle];
IF msg # NIL THEN BlinkMsg[msg]
ELSE {
lenX: INT ← LengthOfVL[xvl];
lenY: INT ← LengthOfVL[yvl];
IF lenX # lenY THEN BlinkMsg[IO.PutFR[
"number of x values = %g, but number of y values = %g.",
IO.int[lenX], IO.int[lenY]]]
ELSE IF lenX # entity.group.length THEN BlinkMsg[IO.PutFR[
"number of values should be %g but there are only %g.",
IO.int[entity.group.length], IO.int[lenX]]]
ELSE { OPEN handle;
-- length of x, y, and group x are the same.
sameX, sameY: BOOL;
plotExits: BOOL ← chart.viewer # NIL;
plotted: BOOL ← EntityFromId[graph.entityList, entity.id] # NIL;
IF NOT plotted THEN {
IF entity.group.x.segments = NIL THEN InitSegEnd[entity.group.x];
InitSegAll[entity];
graph.entityList ← AppendEntityList[graph.entityList, CONS[entity, NIL]];
};
sameX ← AlmostSameVL[xvl, GraphConvert.VLFromSDL[entity.group.x.segments]];
sameY ← AlmostSameVL[yvl, GraphConvert.VLFromSDL[entity.segments]];
IF sameX THEN {
IF NOT sameY THEN {
IF plotExits AND plotted THEN PaintEntity[handle, erase, entity, TRUE];
UpdateSegAll[entity, yvl];
};
}
ELSE { -- x changed, whether same y or not.
UpdateSegEnd[entity.group.x, xvl];
FOR el: EntityList ← handle.graph.entityList, el.rest UNTIL el = NIL DO
SetSegments[el.first];
ENDLOOP;
};
IF plotExits THEN {
IF sameX THEN {IF NOT sameY THEN PaintEntity[handle, paint, entity, TRUE]}
ELSE PaintAll[handle];
};
};
};
xvl ← GraphCleanUp.CleanUpVL[xvl];
yvl ← GraphCleanUp.CleanUpVL[yvl];
lastX ← GraphCleanUp.CleanUpVL[lastX];
lastY ← GraphCleanUp.CleanUpVL[lastY];
}; -- UpdateXYValues
AlmostSameVL: PROC [vla, vlb: ValueList] RETURNS [BOOL] = {
va: ValueList ← vla;
vb: ValueList ← vlb;
DO
IF va = NIL THEN {
IF vb = NIL THEN RETURN[TRUE]
ELSE RETURN[FALSE];
}
ELSE IF vb = NIL THEN RETURN[FALSE];
IF NOT Almost[va.first, vb.first] THEN RETURN[FALSE];
va ← va.rest;
vb ← vb.rest;
ENDLOOP;
}; -- AlmostSameVL
UpdateEntityGroup: PROC[handle: GraphHandle, eg: EntityGroup] = { OPEN handle;
}; -- UpdateEntityGroup
UpdateCrosssection: PROC[handle: GraphHandle, x: REAL] = { OPEN handle;
rope, tRope: ROPE;
ok: BOOL;
y: REAL;
FOR egl: EntityGroupList ← graph.entityGroupList, egl.rest UNTIL egl = NIL DO
xEntity: Entity ← egl.first.x;
rope ← IF rope = NIL THEN "[" ELSE rope.Concat[", ["];
FOR el: EntityList ← egl.first.entityList, el.rest UNTIL el = NIL DO
IF el.first = xEntity THEN LOOP;
[ok, y] ← Crosssection[xEntity.newValues, el.first, x];
tRope ← IF ok THEN Convert.RopeFromReal[y] ELSE "(*)";
rope ← IF rope = NIL THEN tRope ELSE rope.Cat[" ", tRope];
ENDLOOP;
rope.Concat["]"];
ENDLOOP;
ViewerTools.SetContent[controller.yIds, rope];
}; -- UpdateCrosssection
UpdateFromIntField: PROC [field: Viewer, origianl: INT ← 0, showMsg: BOOLTRUE] RETURNS [int: INT ← 0] = {
caller should make sure that field is not nil.
msg: ROPE;
[msg, int] ← GetIntField[field, showMsg];
IF msg # NIL THEN int ← origianl;
}; -- UpdateFromIntField
UpdateFromRealField: PROC [field: Viewer, origianl: REAL ← 0.0, showMsg: BOOLTRUE] RETURNS [real: REAL ← 0.0] = {
caller should make sure that field is not nil.
msg: ROPE;
[msg, real] ← GetRealField[field, showMsg];
IF msg # NIL THEN real ← origianl;
}; -- UpdateFromRealField
}.
LOG.
SChen, created at October 9, 1985 8:57:21 pm PDT.