CDPanelImpl.mesa (part of ChipNDale)
Copyright © 1983, 1985, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, August 8, 1983 5:20 pm
Last Edited by: Christian Jacobi, August 25, 1986 6:29:43 pm PDT
DIRECTORY
Buttons,
CD,
CDCells,
CDCommandOps,
CDEnvironment,
CDEvents,
CDLayers,
CDPanel,
CDPanelExtras,
CDPrivate,
CDSequencer,
CDValue,
CDViewer,
Containers,
Labels,
Menus,
Rope,
TerminalIO,
UserProfile,
ViewerEvents,
ViewerClasses,
ViewerOps,
ViewerTools;
CDPanelImpl:
CEDAR
MONITOR
IMPORTS Buttons, CD, CDCells, CDCommandOps, CDEnvironment, CDEvents, CDLayers, CDPrivate, CDSequencer, CDValue, CDViewer, Containers, Labels, Rope, TerminalIO, UserProfile, ViewerEvents, ViewerOps, ViewerTools
EXPORTS CDPanel, CDPanelExtras
SHARES CDLayers, CDPrivate =
BEGIN
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
panelKey: REF INT ~ NEW[INT]; -- used instead of atoms, to be really unique
panelClassKey: REF INT ~ NEW[INT];
Panel: TYPE = REF PanelRecord; -- one per design
PanelRecord:
TYPE =
RECORD [
container: Viewer←NIL,
design: CD.Design,
class: PanelClass←NIL,
nextLayerX: CARDINAL,
nextLayerY: CARDINAL,
nextX: CARDINAL,
nextY: CARDINAL,
nextSpecialX: CARDINAL,
layerLabel: Labels.Label,
layerWidths: LIST OF WidthValueRef ← NIL,
firstLayer: REF LayerDefine ← NIL,
tripples: LIST OF REF Tripple ← NIL
];
PanelList: TYPE = LIST OF Panel;
globalClass: PanelClass ~ NEW[PanelEntryList←NIL];
panelList: PanelList ← NIL;
GetPanel:
PROC [design:
CD.Design]
RETURNS [Panel] =
BEGIN
x: REF ← CDValue.Fetch[boundTo: design, key: panelKey, propagation: global];
IF x=
NIL
THEN {
panel: Panel = NEW[PanelRecord];
panel.class ← GetPanelClass[design.technology];
panel.design ← design;
[] ← CDValue.StoreConditional[design, panelKey, panel];
RETURN [GetPanel[design]]
};
RETURN [NARROW[x, Panel]];
END;
GetPanelClass:
PROC [tech:
CD.Technology]
RETURNS [PanelClass] =
BEGIN
IF tech=NIL THEN RETURN [globalClass]
ELSE {
x: REF ← CDValue.Fetch[boundTo: tech, key: panelClassKey, propagation: technology];
IF x=
NIL
THEN {
panelClass: PanelClass = NEW[PanelEntryList←NIL];
[] ← CDValue.StoreConditional[boundTo: tech, key: panelClassKey, value: panelClass];
RETURN [GetPanelClass[tech]];
};
RETURN [NARROW[x, PanelClass]];
}
END;
CreatePanel:
PUBLIC
ENTRY
PROC [design:
CD.Design]
RETURNS [Viewer] =
--only one panel-viewer per design is created
--panel may or may not be updated if definitions occur after first creation
BEGIN ENABLE UNWIND => NULL;
panel: Panel ← GetPanel[design];
panelClass: PanelClass ← GetPanelClass[design.technology];
IF panel.container#NIL AND NOT panel.container.destroyed THEN RETURN [panel.container];
panel.container ← NIL;
panel.tripples ← NIL;
--supress creation of viewer if empty
IF panelClass#NIL AND panelClass^#NIL THEN CreatePanelViewer[panel];
CheckPanelList[panel];
IF panel.container#
NIL
THEN {
ViewerOps.PaintViewer[panel.container, all];
IF ~UserProfile.Boolean["ChipNDale.ControlViewerOpenIconic",
FALSE]
THEN
ViewerOps.OpenIcon[panel.container];
};
RETURN [panel.container]
END;
AppendEntryInClass:
INTERNAL
PROC [class: PanelClass, entry:
REF
ANY] =
BEGIN
IF class^=NIL THEN class^ ← LIST[entry]
ELSE
FOR list: PanelEntryList ← class^, list.rest
DO
IF list.rest = NIL THEN {list.rest ← LIST[entry]; EXIT}
ENDLOOP;
END;
AppendEntryInViewers:
INTERNAL
PROC [class: PanelClass, entry:
REF
ANY] =
BEGIN
FOR list: PanelList ← panelList, list.rest
WHILE list#
NIL
DO
IF list.first.container#
NIL
AND ~list.first.container.destroyed
THEN {
IF list.first.class=class OR class=globalClass THEN NewEntry[list.first, entry];
}
ENDLOOP
END;
CheckPanelList:
INTERNAL
PROC [p: Panel] =
BEGIN
copiedList: PanelList ← NIL;
FOR list: PanelList ← panelList, list.rest
WHILE list#
NIL
DO
IF list.first.container#
NIL
AND ~list.first.container.destroyed
AND list.first#p
THEN
copiedList ← CONS[list.first, copiedList]
ENDLOOP;
IF p#NIL THEN copiedList ← CONS[p, copiedList];
panelList ← copiedList
END;
AppendEntry:
INTERNAL
PROC [class: PanelClass, entry:
REF
ANY] =
BEGIN
AppendEntryInClass[class, entry];
AppendEntryInViewers[class, entry];
END;
DefineNewLine:
PUBLIC
ENTRY
PROC [tech:
CD.Technology] =
BEGIN ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
AppendEntry[class, $NewLine];
END;
DefineButton:
PUBLIC
ENTRY
PROC [tech:
CD.Technology←
NIL, name:
ROPE, proc: CDSequencer.CommandProc ←
NIL, command:
ATOM ←
NIL, queue: CDSequencer.QueueMethod ← useDefault, topLine:
BOOL ←
FALSE, border:
BOOL ←
FALSE,data:
REF ←
NIL, cdValueKey:
REF ←
NIL] =
BEGIN
ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
bd: REF ButtonDefine;
IF command=NIL AND queue=useDefault THEN queue ← doQueue;
bd ←
NEW[ButtonDefine ← [
name: name,
proc: proc, command: command, queue: queue, data: data,
border: border, topLine: topLine, cdValueKey: cdValueKey
]];
AppendEntry[class, bd];
END;
DefineLabel:
PUBLIC
ENTRY
PROC [tech:
CD.Technology←
NIL, name:
ROPE, border:
BOOL ←
FALSE, cdValueKey:
REF ←
NIL] =
BEGIN ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
lab: REF LabelDefine;
lab ← NEW[LabelDefine ← [name: name, border: border, cdValueKey: cdValueKey]];
AppendEntry[class, lab];
END;
layerDefinitions:
REF
ARRAY [0..
CD.layerNum)
OF
REF LayerDefine =
NEW[ARRAY [0..CD.layerNum) OF REF LayerDefine ← ALL[NIL]];
LayerText:
PROC [lev:
CD.Layer]
RETURNS [
ROPE] =
BEGIN
RETURN [
IF layerDefinitions[lev]#
NIL
THEN layerDefinitions[lev].text
ELSE "not defined"
]
END;
LayerDefine:
TYPE =
RECORD [
layer: CD.Layer ← CD.undefLayer,
text: ROPE ← NIL,
min, default: CD.Number ← 0
];
IntDefine:
TYPE =
RECORD [
cdValueKey: REF,
text: ROPE,
min, max, default: INT,
lambda: INT ← 1
];
ButtonDefine:
TYPE =
RECORD [
name: ROPE,
proc: CDSequencer.CommandProc ← NIL,
command: ATOM ← NIL,
queue: CDSequencer.QueueMethod,
topLine: BOOL ← FALSE,
border: BOOL ← FALSE,
data: REF ← NIL,
cdValueKey: REF ← NIL
];
LabelDefine:
TYPE =
RECORD [
name: ROPE,
cdValueKey: REF,
border: BOOL ← FALSE
];
TextDefine:
TYPE =
RECORD [
cdValueKey: REF,
width: INT ← -1, --viewer units
buttonText: Rope.ROPE,
editable: BOOL ← TRUE,
border: BOOL ← FALSE
];
PanelEntryList: TYPE = LIST OF REF ANY; -- one per CD.Technology
PanelClass: TYPE = REF PanelEntryList;
--Compensations
--the viewer package uses funny y positions; use this to compensate
butYCompensation: INTEGER ← 0;
labelYCompensation: INTEGER ← 1;
textYCompensation: INTEGER ← -2;
--the height sometimes are not enogh to reasonably display contents...
textHCompensation: INTEGER ← 2;
DefineLayerEntry:
PUBLIC
ENTRY
PROC [tech:
CD.Technology, lev:
CD.Layer, text:
ROPE, min, default:
CD.Number𡤁] =
BEGIN
ENABLE UNWIND => NULL;
panelClass: PanelClass = GetPanelClass[tech];
IF lev=CD.undefLayer THEN ERROR;
IF layerDefinitions[lev]#
NIL
THEN
RETURN WITH ERROR CD.Error[doubleRegistration, "re-registers layer"];
layerDefinitions[lev] ←
NEW[LayerDefine ← [
layer: lev, text: text, min: min, default: default
]];
AppendEntry[panelClass, layerDefinitions[lev]];
CDLayers.SetLayerWidth[design: NIL --!!! it sets default--, layer: lev, width: default];
END;
NotifyCurrentLayer: CDLayers.DesignNotifyProc =
BEGIN
panel: Panel = GetPanel[design];
IF panel.layerLabel#
NIL
THEN {
l: CD.Layer ← CDLayers.CurrentLayer[design];
Labels.Set[panel.layerLabel, LayerText[l]];
}
END;
NotifyLayerWidth: CDLayers.LayerNotifyProc =
BEGIN
panel: Panel = GetPanel[design];
IF panel.layerLabel#
NIL
THEN {
FOR list:
LIST
OF WidthValueRef ← panel.layerWidths, list.rest
WHILE list#
NIL
DO
IF list.first.layerDefine.layer=layer
THEN {
Labels.Set[list.first.numbLab,
CDCommandOps.LambdaRope[
n: CDLayers.LayerWidth[design, layer],
lambda: design.technology.lambda
]
];
EXIT;
};
ENDLOOP;
}
END;
-- Viewer Stuff -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
topY: CARDINAL = 1;
entryHSpace: CARDINAL = 3;
entryHeight: CARDINAL = 12;
shorterEntryVSpace: CARDINAL = 1;
DesignName:
PROC [d:
CD.Design]
RETURNS [Rope.
ROPE] = {
RETURN [IF d.name#NIL THEN d.name ELSE "no name" ];
};
Caption:
PROC [panel: Panel]
RETURNS [
ROPE] = {
RETURN [Rope.Cat[
DesignName[panel.design],
" ",
panel.design.technology.name,
" ",
CDCells.PushedCellName[panel.design]
]];
};
CreatePanelViewer:
INTERNAL
PROC [panel: Panel] =
BEGIN
MakeClassEntries:
INTERNAL
PROC [class: PanelClass] =
--uses intermediate layer variables!
BEGIN
FOR l: PanelEntryList ← class^, l.rest
WHILE l#
NIL
DO
NewEntry[panel, l.first];
ENDLOOP;
END;
IF panel=NIL OR panel.design=NIL OR panel.design.technology=NIL THEN ERROR;
TerminalIO.WriteRopes["create control panel for ", DesignName[panel.design], "\n"];
panel.tripples ← NIL;
panel.layerWidths ← NIL;
panel.nextLayerX ← panel.nextX ← 0;
panel.nextY ← topY;
panel.nextLayerY ← topY+entryHeight+entryHSpace;
panel.container ← Containers.Create[[
name: Caption[panel],
openHeight: CDValue.FetchInt[panel.design, $PanelHeight, global, 120],
scrollable: TRUE,
iconic: TRUE, column: right, icon: CDEnvironment.GetPanelIcon[panel.design]
]];
ViewerOps.AddProp[panel.container, $ChipNDaleDesign, panel.design];
ViewerOps.AddProp[panel.container, $CDPanelPrivate, panel];
[] ← NextLabel[panel, "current layer:"];
panel.layerLabel ← NextLabel[panel: panel,
extraSpaces: 2,
name: LayerText[CDLayers.CurrentLayer[panel.design]],
extraWidth: 2
];
[] ← NextLabel[panel, "| "];
panel.nextSpecialX ← panel.nextX;
panel.nextY ← 3*(entryHeight+entryHSpace);
panel.nextX ← 0;
MakeClassEntries[panel.class];
MakeClassEntries[globalClass];
IF panel.firstLayer#
NIL
THEN
CDLayers.SetCurrentLayer[panel.design, panel.firstLayer.layer];
END;
NewEntry:
INTERNAL
PROC[panel: Panel, entry:
REF] =
BEGIN
IF panel.container.destroyed THEN RETURN;
WITH entry
SELECT
FROM
layerDefine:
REF LayerDefine => {
IF panel.firstLayer=NIL THEN panel.firstLayer ← layerDefine;
CreateLayerEntry[panel, layerDefine];
};
intDef: REF IntDefine => CreateIntEntry[panel, intDef];
butDef: REF ButtonDefine => CreateButtEntry[panel, butDef];
labDef: REF LabelDefine => [] ← CreateLabelEntry[panel, labDef];
tDef: REF TextDefine => [] ← CreateTextEntry[panel, tDef];
a:
ATOM => {
SELECT a
FROM
$NewLine => CreateLnEntry[panel];
ENDCASE => ERROR;
};
ENDCASE => ERROR;
END;
RepaintCaptions:
ENTRY CDEvents.EventProc =
BEGIN
panel: Panel ← GetPanel[design];
IF panel.container#
NIL
THEN {
panel.container.name ← Caption[panel];
ViewerOps.PaintViewer[panel.container, caption];
};
WidthValueRec:
TYPE =
RECORD [
layerDefine: REF LayerDefine,
panel: Panel,
numbLab: Labels.Label ← NIL
];
WidthValueRef: TYPE = REF WidthValueRec;
NextIntButton:
INTERNAL
PROC [panel: Panel, label:
ROPE, proc: Buttons.ButtonProc, border:
BOOL ←
FALSE, clientData:
REF
ANY ←
NIL] =
BEGIN
yoff: INT = Containers.ScrollOffset[panel.container];
button: Buttons.Button = Buttons.Create[
info: [ name: label,
wx: panel.nextX,
wy: panel.nextY+yoff+butYCompensation,
wh: entryHeight,
parent: panel.container,
border: border
],
clientData: clientData,
proc: proc
];
panel.nextX ← button.wx+button.ww+entryHSpace;
END;
NextButton:
INTERNAL
PROC [panel: Panel, label:
ROPE, proc: Buttons.ButtonProc, clientData:
REF
ANY ←
NIL, topLine:
BOOL ←
FALSE, border:
BOOL ←
FALSE]
RETURNS [button: Buttons.Button] =
BEGIN
yoff: INT = Containers.ScrollOffset[panel.container];
x: INT ← panel.nextX;
y: INT ← panel.nextY;
IF topLine THEN {x ← panel.nextSpecialX; y ← 0};
button ← Buttons.Create[
info: [ name: label,
wx: x,
wy: y+yoff+butYCompensation,
wh: entryHeight,
parent: panel.container,
border: border
],
clientData: clientData,
proc: proc
];
IF topLine THEN panel.nextSpecialX ← button.wx+button.ww+entryHSpace
ELSE panel.nextX ← button.wx+button.ww+entryHSpace
END;
NextLabel:
INTERNAL
PROC [panel: Panel, name:
ROPE, border:
BOOL ←
FALSE, extraSpaces:
CARDINAL ← 0, extraWidth:
CARDINAL ← 0]
RETURNS [Labels.Label] =
BEGIN
yoff: INT = Containers.ScrollOffset[panel.container];
label: Labels.Label;
IF name=NIL THEN name ← " ";
WHILE extraWidth>0
DO
name ← Rope.Concat[base: name, rest: " "];
extraWidth ← extraWidth-1;
ENDLOOP;
label ← Labels.Create[
info: [ name: name,
wx: panel.nextX+extraSpaces*entryHSpace,
wy: panel.nextY+yoff+labelYCompensation,
wh: entryHeight,
parent: panel.container,
border: border
]
];
panel.nextX ← label.wx+label.ww+entryHSpace;
RETURN [label]
END;
CreateIntEntry:
INTERNAL
PROC [panel: Panel, intDef:
REF IntDefine] =
BEGIN
initialValue: ROPE;
intRef: REF Tripple ← NEW[Tripple ← [panel: panel, define: intDef]];
lambda: INT ← IF intDef.lambda<=0 THEN panel.design.technology.lambda ELSE intDef.lambda;
[] ← NextIntButton[panel: panel, label: intDef.text, proc: IntCalled, clientData: intRef];
initialValue ← CDCommandOps.LambdaRope[
n: CDValue.FetchInt[
boundTo: panel.design,
key: intDef.cdValueKey,
propagation: technology,
ifNotFound: intDef.default
],
lambda: lambda
];
intRef.feedback ← NextLabel[panel: panel, name: initialValue, extraWidth: 8];
panel.tripples ← CONS[intRef, panel.tripples];
END;
Tripple: TYPE = RECORD [panel: Panel, define: REF ← NIL, feedback: REF ← NIL];
CreateLabelEntry:
INTERNAL
PROC [panel: Panel, labDef:
REF LabelDefine]
RETURNS [tripple:
REF Tripple←
NIL] =
BEGIN
lab: Labels.Label ← NextLabel[
panel: panel,
name: labDef.name,
border: labDef.border
];
IF labDef.cdValueKey#
NIL
THEN {
tripple ← NEW[Tripple ← [panel: panel, define: labDef, feedback: lab]];
panel.tripples ← CONS[tripple, panel.tripples];
RedisplayLabel[tripple];
}
END;
FetchRope:
PROC [from:
REF, key:
REF]
RETURNS [
ROPE] = {
WITH CDValue.Fetch[from, key, global]
SELECT
FROM
r: ROPE => RETURN [r];
rt: REF TEXT => RETURN [Rope.FromRefText[rt]];
ENDCASE => RETURN [NIL];
};
NextName:
PROC [list:
LIST
OF
ROPE, last:
ROPE←
NIL]
RETURNS [next:
ROPE ←
NIL] = {
IF list=NIL THEN RETURN;
FOR l:
LIST
OF
ROPE ← list, l.rest
WHILE l#
NIL
DO
IF Rope.Equal[last, l.first, FALSE] THEN RETURN [IF l.rest=NIL THEN list.first ELSE l.rest.first]
ENDLOOP;
RETURN [list.first]
};
FetchOneRope:
PROC [from:
REF, key:
REF, start:
ROPE←
NIL]
RETURNS [
ROPE] = {
WITH CDValue.Fetch[from, key, global]
SELECT
FROM
r: ROPE => RETURN [r];
rt: REF TEXT => RETURN [Rope.FromRefText[rt]];
lr: LIST OF ROPE => RETURN [NextName[lr, start]];
ENDCASE => RETURN [NIL];
};
TextButProc: Menus.ClickProc = {
--called from special buttons which have a Text as tripple.feedback
tripple: REF Tripple ← NARROW[clientData];
tsDef: REF TextDefine ← NARROW[tripple.define];
selection: REF ViewerTools.SelPosRec ← NIL;
v: Viewer ← NARROW[tripple.feedback]; --not the button; the text
SELECT
TRUE
FROM
mouseButton=blue => ViewerTools.SetContents[v, NIL];
ViewerTools.GetSelectedViewer[]=v => {
--viewer previously selected; iterate through.
contents: ROPE ← FetchOneRope[tripple.panel.design.technology, tsDef.cdValueKey, ViewerTools.GetContents[v]];
ViewerTools.SetContents[v, contents];
selection ← NEW[ViewerTools.SelPosRec ← [start: contents.Length[], length: 0]];
};
ENDCASE => NULL;
ViewerTools.SetSelection[v, selection];
--new contents is not stored to CDValue yet!! (It wont if edited either)
};
TextLabButProc: Menus.ClickProc = {
--called from special buttons which have a Label as tripple.feedback
tripple: REF Tripple ← NARROW[clientData];
tsDef: REF TextDefine ← NARROW[tripple.define];
v: Viewer ← NARROW[tripple.feedback]; --not the button; the label
contents: ROPE ← FetchRope[tripple.panel.design, tsDef.cdValueKey];
contents ← FetchOneRope[tripple.panel.design.technology, tsDef.cdValueKey, contents];
CDValue.Store[tripple.panel.design, tsDef.cdValueKey, contents];
Labels.Set[v, contents];
};
CreateTextEntry:
INTERNAL
PROC [panel: Panel, tsDef:
REF TextDefine]
RETURNS [tripple:
REF Tripple←
NIL] =
BEGIN
yoff: INT = Containers.ScrollOffset[panel.container];
w: INT ← IF tsDef.width<=0 THEN 2000 ELSE MIN[tsDef.width, 2000];
h: INT ← entryHeight;
y: INT ← panel.nextY+yoff;
x: INT ← panel.nextX;
v: Viewer;
tripple ← NEW[Tripple ← [panel: panel, define: tsDef, feedback: NIL]];
IF ~Rope.IsEmpty[tsDef.buttonText]
THEN {
button: Buttons.Button ← Buttons.Create[
info: [ name: tsDef.buttonText,
wx: x, wy: y+butYCompensation, wh: h,
border: FALSE,
parent: panel.container
],
clientData: tripple,
proc: IF tsDef.editable THEN TextButProc ELSE TextLabButProc
];
x ← button.wx+button.ww+entryHSpace;
};
IF tsDef.editable
THEN
v ← ViewerTools.MakeNewTextViewer[info: [
wx: x, wy: y+textYCompensation, ww: w, wh: h+textHCompensation,
parent: panel.container,
border: FALSE,
data: FetchOneRope[panel.design, tsDef.cdValueKey]
]]
ELSE
v ← Labels.Create[info: [
name: FetchOneRope[panel.design, tsDef.cdValueKey],
wx: x, wy: y+labelYCompensation, ww: w, wh: h,
parent: panel.container,
border: FALSE
]];
tripple.feedback ← v;
panel.nextX ← v.wx+w+entryHSpace;
IF tsDef.width<=0 THEN Containers.ChildXBound[panel.container, v];
panel.tripples ← CONS[tripple, panel.tripples];
END;
RedisplayLabel:
PROC [tripple:
REF Tripple] =
BEGIN
IF tripple=NIL THEN RETURN;
WITH tripple.define
SELECT
FROM
labDef:
REF LabelDefine => {
x: REF = CDValue.Fetch[tripple.panel.design, labDef.cdValueKey, global];
Labels.Set[NARROW[tripple.feedback], CDCommandOps.ToRope[x, "-?-"]];
};
butDef:
REF ButtonDefine => {
x: REF = CDValue.Fetch[tripple.panel.design, butDef.cdValueKey, global];
Buttons.ReLabel[NARROW[tripple.feedback], CDCommandOps.ToRope[x, "-?-"]];
};
ENDCASE =>
WITH tripple.feedback
SELECT
FROM
t: REF Tripple => RedisplayLabel[t]
ENDCASE => NULL;
END;
RedisplayLabels:
PUBLIC
PROC [design:
CD.Design] =
BEGIN
panel: Panel = GetPanel[design];
IF panel.container=NIL OR panel.container.destroyed THEN RETURN;
FOR list:
LIST
OF
REF Tripple ← panel.tripples, list.rest
WHILE list#
NIL
DO
RedisplayLabel[list.first];
ENDLOOP;
END;
CreateButtEntry:
INTERNAL
PROC [panel: Panel, butDef:
REF ButtonDefine] =
BEGIN
but: Buttons.Button = NextButton[
panel: panel,
label: butDef.name,
proc: ButtonCalled,
border: butDef.border,
topLine: butDef.topLine,
clientData: butDef
];
IF butDef.cdValueKey#
NIL
THEN {
tripple: REF Tripple ← NEW[Tripple ← [panel: panel, define: butDef, feedback: but]];
panel.tripples ← CONS[tripple, panel.tripples];
RedisplayLabel[tripple];
}
END;
ButtonCalled: Buttons.ButtonProc =
BEGIN
butDef: REF ButtonDefine = NARROW[clientData];
comm: CDSequencer.Command =
NEW[CDSequencer.CommandRec←[
data: butDef.data,
design: CDViewer.DesignOf[NARROW[parent]]
]];
IF butDef.proc#
NIL
THEN
CDSequencer.ExecuteProc[comm: comm, proc: butDef.proc, queue: butDef.queue]
ELSE
IF butDef.command#
NIL
THEN
CDSequencer.ExecuteCommand[comm: comm, key: butDef.command, queue: butDef.queue];
END;
Double:
PROC[i:
INT]
RETURNS [
INT] =
INLINE {
IF i<LAST[INT]/2 AND i>(FIRST[INT]/2) THEN i ← i+i;
RETURN [i]
};
Inc:
PROC[i:
INT, x:
INT𡤁]
RETURNS [
INT] =
INLINE {
IF i<=LAST[INT]-x THEN i ← i+x;
RETURN [i]
};
Dec:
PROC[i:
INT, x:
INT𡤁]
RETURNS [
INT] =
INLINE {
IF i>=FIRST[INT]+x THEN i ← i-x;
RETURN [i]
};
GetAnInt:
PROC [old, default:
INT, label:
ROPE, lambda:
INT𡤁]
RETURNS [new:
INT] =
BEGIN
ENABLE TerminalIO.UserAbort => GOTO aborted;
choice: LIST OF ROPE;
new ← old;
IF lambda=1
THEN
choice ← LIST["+1", "-1", "*2", "/2", "default", "type"]
ELSE
choice ← LIST["+1", "-1", "*2", "/2", "default", "type", "type int", "trunc"];
SELECT TerminalIO.RequestSelection[label: label, choice: choice]
FROM
1 => new ← Inc[old, lambda];
2 => new ← Dec[old, lambda];
3 => {new ← Double[old]};
4 => {new ← old/2};
5 => {new ← default};
6 => {new ← TerminalIO.RequestInt["type value > "]*lambda};
7 => {new ← TerminalIO.RequestInt["type value (int) > "]};
8 => {new ← old/lambda*lambda};
ENDCASE => TerminalIO.WriteRope["Skipped\n"];
EXITS aborted => NULL;
END;
IntCalled: Buttons.ButtonProc =
BEGIN
design: CD.Design ← CDViewer.DesignOf[NARROW[parent]];
IF design=NIL THEN RETURN;
CDSequencer.ExecuteProc[
proc: SerializedIntCalled,
design: design,
queue: doQueue,
comm:
NEW[CDSequencer.CommandRec ← [
data: clientData,
key:
SELECT mouseButton
FROM
red => $left,
yellow => $middle,
blue => $right,
ENDCASE => NIL,
n: IF control THEN 1 ELSE 0,
b: shift
]]
];
END;
SerializedIntCalled:
PROC [comm: CDSequencer.Command] =
BEGIN
ENABLE UNWIND => NULL;
i: INT;
design: CD.Design ~ comm.design;
tripple: REF Tripple = NARROW[comm.data];
intDef: REF IntDefine = NARROW[tripple.define];
lambda: INT ← intDef.lambda;
IF lambda<=0 THEN lambda ← design.technology.lambda;
i ← CDValue.FetchInt[
boundTo: design,
key: intDef.cdValueKey,
propagation: global,
ifNotFound: intDef.default
];
IF comm.b
THEN {
IF comm.n=1 THEN i ← i/lambda*lambda
ELSE i ← GetAnInt[i, intDef.default, intDef.text, lambda]
}
ELSE
IF comm.key=$right
THEN {
IF comm.n=1 THEN i←i/2 ELSE i ← Dec[i, lambda]
}
ELSE
IF comm.key=$left
THEN {
IF comm.n=1 THEN i ← Double[i] ELSE i ← Inc[i, lambda]
};
i ← MAX[MIN[i, intDef.max], intDef.min];
CDValue.StoreInt[design, intDef.cdValueKey, i];
Labels.Set[NARROW[tripple.feedback], CDCommandOps.LambdaRope[n: i, lambda: lambda]];
END;
CreateLnEntry:
INTERNAL
PROC [panel: Panel] =
BEGIN
panel.nextY ← panel.nextY+entryHSpace+entryHeight;
panel.nextX ← 0;
END;
CreateLayerEntry:
INTERNAL
PROC [panel: Panel, layerDefine:
REF LayerDefine] =
BEGIN
yoff: INT = Containers.ScrollOffset[panel.container];
p: WidthValueRef ←
NEW[WidthValueRec ←
WidthValueRec[layerDefine: layerDefine, panel: panel]
];
button: Buttons.Button = Buttons.Create[
info: [ name: layerDefine.text,
wx: panel.nextLayerX,
wy: panel.nextLayerY+yoff+butYCompensation,
wh: entryHeight,
parent: panel.container,
border: FALSE
],
clientData: p,
proc: WireWidthCalled
];
p.numbLab ← Labels.Create[
info: [
wx: panel.nextLayerX,
wy: panel.nextLayerY+shorterEntryVSpace+entryHeight+yoff+labelYCompensation,
wh: entryHeight,
ww: button.ww+4*entryHSpace, --2 spaces for real; 2 covering leading blank of next #
parent: panel.container,
border: FALSE,
name: CDCommandOps.LambdaRope[
n: CDLayers.LayerWidth[panel.design, layerDefine.layer],
lambda: panel.design.technology.lambda
]
]
];
panel.nextLayerX ← button.wx+button.ww+2*entryHSpace;
panel.layerWidths ← CONS[p, panel.layerWidths];
END;
WireWidthCalled: Buttons.ButtonProc =
BEGIN
wireRef: WidthValueRef = NARROW[clientData];
CDSequencer.ExecuteProc[
proc: SerializedWireWidthCalled,
design: wireRef.panel.design,
queue: doQueue,
comm:
NEW[CDSequencer.CommandRec ← [
data: clientData,
key:
SELECT mouseButton
FROM
red => $left,
yellow => $middle,
blue => $right,
ENDCASE => NIL,
n: IF control THEN 1 ELSE 0,
b: shift
]]
];
END;
Serial
izedWireWidthCalled:
PROC[comm: CDSequencer.Command] =
BEGIN
wireRef: WidthValueRef = NARROW[comm.data];
lev: CD.Layer = wireRef.layerDefine.layer;
design: CD.Design ← wireRef.panel.design;
width: CD.Number ← CDLayers.LayerWidth[design, lev];
lambda: INT ← design.technology.lambda;
IF comm.b
THEN {
IF comm.n=1 THEN width ← width/lambda*lambda
ELSE width ← GetAnInt[width, wireRef.layerDefine.default, wireRef.layerDefine.text, lambda]
}
ELSE
IF comm.key=$right
THEN {
IF comm.n=1 THEN width ← width/2 ELSE width ← Dec[width, lambda]
}
ELSE
IF comm.key=$left
THEN {
IF comm.n=1 THEN width ← Double[width] ELSE width ← Inc[width, lambda]
}
ELSE
IF comm.key=$middle
THEN {
CDLayers.SetCurrentLayer[design, lev];
RETURN
};
width ← MAX[width, 0];
CDLayers.SetLayerWidth[design, lev, width];
END;
DefineIntEntry:
PUBLIC
ENTRY
PROC [tech:
CD.Technology, cdValueKey:
REF, text:
ROPE, min:
INT, max:
INT, default:
INT, lambda:
INT] = {
ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
def: REF IntDefine ← NEW[IntDefine ← [cdValueKey: cdValueKey, text: text, min: min, max: max, default: default, lambda: lambda]];
CDValue.StoreInt[boundTo: tech, key: cdValueKey, value: default];
AppendEntry[class, def];
};
DefineTextEntry:
PUBLIC
ENTRY
PROC [tech:
CD.Technology ←
NIL, cdValueKey:
REF, button: Rope.
ROPE ←
NIL, width:
INT ← -1, editable:
BOOL ←
TRUE] =
BEGIN ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
def: REF TextDefine = NEW[TextDefine ← [cdValueKey: cdValueKey, width: width, border: FALSE, buttonText: button, editable: editable]];
AppendEntry[class, def];
END;
FromDisplay:
PROC [design:
CD.Design, cdValueKey:
REF]
RETURNS [Rope.
ROPE←
NIL] =
BEGIN
panel: Panel = GetPanel[design];
FOR list:
LIST
OF
REF Tripple ← panel.tripples, list.rest
WHILE list#
NIL
DO
WITH list.first.define
SELECT
FROM
tsDef:
REF TextDefine =>
IF tsDef.cdValueKey=cdValueKey
THEN {
RETURN [ViewerTools.GetContents[NARROW[list.first.feedback]]];
};
ENDCASE => NULL;
ENDLOOP;
END;
FromDisplayRope:
PUBLIC
PROC [design:
CD.Design, cdValueKey:
REF]
RETURNS [Rope.
ROPE] =
BEGIN
x: REF ← FromDisplay[design, cdValueKey];
CDValue.Store[design, cdValueKey, x];
WITH x
SELECT
FROM
r: Rope.ROPE => RETURN [r];
ENDCASE => RETURN [NIL];
END;
ReDisplayNoStore:
PROC [design:
CD.Design, cdValueKey:
REF, rope: Rope.
ROPE] = {
panel: Panel = GetPanel[design];
IF panel.container=NIL OR panel.container.destroyed THEN RETURN;
FOR list:
LIST
OF
REF Tripple ← panel.tripples, list.rest
WHILE list#
NIL
DO
WITH list.first.define
SELECT
FROM
tDef:
REF TextDefine =>
IF tDef.cdValueKey=cdValueKey
THEN {
v: Viewer ← NARROW[list.first.feedback];
IF v#
NIL
THEN {
IF v.class.flavor=$Label THEN Labels.Set[v, rope]
ELSE ViewerTools.SetContents[v, rope];
};
};
labDef:
REF LabelDefine =>
IF labDef.cdValueKey=cdValueKey
THEN {
v: Viewer ← NARROW[list.first.feedback];
IF v#NIL THEN Labels.Set[v, rope];
};
butDef:
REF ButtonDefine =>
IF butDef.cdValueKey=cdValueKey
THEN {
v: Viewer ← NARROW[list.first.feedback];
IF v#NIL THEN Buttons.ReLabel[v, rope];
};
intDef:
REF IntDefine =>
IF intDef.cdValueKey=cdValueKey
THEN {
v: Viewer ← NARROW[list.first.feedback];
IF v#
NIL
THEN {
n: INT ← CDValue.FetchInt[design, intDef.cdValueKey, technology, intDef.default];
lambda: INT ← IF intDef.lambda<=0 THEN design.technology.lambda ELSE intDef.lambda;
Buttons.ReLabel[v, CDCommandOps.LambdaRope[n, lambda]];
};
};
ENDCASE => NULL;
ENDLOOP;
};
ReDisplayRope:
PUBLIC
PROC [design:
CD.Design, cdValueKey:
REF, rope: Rope.
ROPE] =
BEGIN
CDValue.Store[design, cdValueKey, rope];
ReDisplayNoStore[design, cdValueKey, rope];
END;
ReDisplay:
PUBLIC
PROC [design:
CD.Design, cdValueKey:
REF] =
BEGIN
rope: ROPE ← FetchRope[design, cdValueKey];
ReDisplayNoStore[design, cdValueKey, rope];
END;
ContainerDeleted: ViewerEvents.EventProc = {
--break circularities (for garbage collection)
WITH ViewerOps.FetchProp[viewer, $CDPanelPrivate]
SELECT
FROM
panel: Panel => {
ViewerOps.AddProp[viewer, $ChipNDaleDesign, NIL];
ViewerOps.AddProp[viewer, $CDPanelPrivate, NIL];
IF panel.container=viewer
AND panel.design#
NIL
THEN {
CDValue.Store[panel.design, panelKey, NIL];
panel.container ← NIL;
panel.design ← NIL;
panel.class ← NIL;
panel.layerLabel ← NIL;
panel.layerWidths ← NIL;
panel.firstLayer ← NIL;
panel.tripples ← NIL;
};
};
ENDCASE => NULL;
};
EnumDesigns:
PROC[p: CDPrivate.DesignEnumerator]
RETURNS [quit:
BOOL←
FALSE] =
BEGIN
FOR list: PanelList ← panelList, list.rest
WHILE list#
NIL
AND ~quit
DO
IF list.first.container#
NIL
AND ~list.first.container.destroyed
THEN {
d: CD.Design ← list.first.design;
IF d#NIL THEN quit ← p[d];
}
ENDLOOP;
END;
--module initialization
[] ← CDValue.RegisterKey[panelKey, NIL];
[] ← CDValue.RegisterKey[panelClassKey, NIL];
CDValue.RegisterKey[key: $PanelHeight];
CDEvents.RegisterEventProc[$RenameDesign, RepaintCaptions];
CDEvents.RegisterEventProc[$AfterPush, RepaintCaptions];
CDEvents.RegisterEventProc[$AfterPop, RepaintCaptions];
CDLayers.RegisterNotifiers[layer: NotifyCurrentLayer, width: NotifyLayerWidth];
[] ← ViewerEvents.RegisterEventProc[ContainerDeleted, destroy, $Container];
CDPrivate.InstallDesignEnumerator[EnumDesigns];
END.