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, Equal],
VFonts USING [EstablishFont],
ViewerTools USING [GetContents, SetContents];
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, TRUE, TRUE];
}; -- 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, TRUE, 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, xy, erase];
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, xy, paint];
};
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, xy, wasOn, erase];
PaintGrids[handle, xy, isOn, paint]; -- 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, text, action];
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: ROPE ← NIL;
add: BOOL ← text = NIL;
nameChanged: BOOL ← FALSE;
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, text, erase];
nameChanged ← NOT rope.Equal[text.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, text, paint];
IF add
THEN {
handle.allTexts ← CONS[text, handle.allTexts];
graph.texts ← CONS[text, graph.texts];
AddTextButton[handle, text];
}
ELSE IF nameChanged THEN 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:
BOOL ←
FALSE] = {
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: ROPE ← NIL;
index: INT ← 0;
add: BOOL ← entity = NIL;
plotted: BOOL ← IF 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, entity, TRUE, paint];
}
ELSE {
-- not adding a new entity
sameX, sameY, nameChanged: BOOL;
newName: ROPE ← ViewerTools.GetContents[controller.entityName];
newCmt: ROPE ← ViewerTools.GetContents[controller.entityCmt];
nameChanged ← NOT (newName.Equal[entity.name] AND newCmt.Equal[entity.comment]);
IF plotExits AND plotted THEN PaintEntity[handle, entity, TRUE, erase];
entity^ ← [
name: newName,
comment: newCmt,
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
];
IF nameChanged THEN 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, entity, TRUE, paint];
}
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, TRUE, TRUE, TRUE];
};
};
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, entity, TRUE, erase];
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, entity, TRUE, paint]}
ELSE PaintAll[handle, TRUE, TRUE, TRUE];
};
};
};
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:
BOOL ←
TRUE]
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:
BOOL ←
TRUE]
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
}.