CDPanelImpl.mesa (part of ChipNDale)
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, August 8, 1983 5:20 pm
last edited by Christian Jacobi, March 25, 1986 4:19:27 pm PST
DIRECTORY
Buttons,
CD,
CDCells,
CDCommandOps,
CDEvents,
CDLayers,
CDPanel,
CDPrivate,
CDSequencer,
CDTipEtc,
CDValue,
Containers,
Labels,
Menus,
Rope USING [Cat, Concat, ROPE],
TerminalIO,
UserProfile,
ViewerEvents,
ViewerClasses,
ViewerOps;
CDPanelImpl:
CEDAR
MONITOR
IMPORTS Buttons, CD, CDCells, CDCommandOps, CDEvents, CDLayers, CDPrivate, CDSequencer, CDTipEtc, CDValue, Containers, Labels, Rope, TerminalIO, UserProfile, ViewerEvents, ViewerOps
EXPORTS CDPanel
SHARES CDLayers, CDPrivate =
BEGIN
Error: ERROR = CODE;
panelKey: REF INT = NEW[INT]; -- used instead of atoms, to be really unique
panelClassKey: REF INT = NEW[INT];
globalClass: PanelClass = NEW[PanelEntryList←NIL];
Panel: TYPE = REF PanelRecord; -- one per design
PanelRecord:
TYPE =
RECORD [
container: ViewerClasses.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,
labels: LIST OF REF Tripple ← NIL
];
panelList: LIST OF Panel ← 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 [ViewerClasses.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.labels ← NIL;
--supress creation of viewer if empty
IF panelClass#NIL AND panelClass^#NIL THEN CreatePanelViewer[panel];
CheckPanelList[panel];
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:
LIST
OF Panel ← 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: LIST OF Panel ← NIL;
FOR list:
LIST
OF Panel ← 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.
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.
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.
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.ROPE ← NIL,
min, default: CD.Number ← 0
];
IntDefine:
TYPE =
RECORD [
cdValueKey: REF,
text: Rope.ROPE,
min, max, default: INT,
lambda: INT ← 1
];
ButtonDefine:
TYPE =
RECORD [
name: Rope.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.ROPE,
cdValueKey: REF,
border: BOOL ← FALSE
];
PanelEntryList: TYPE = LIST OF REF ANY; -- one per CD.Technology
PanelClass: TYPE = REF PanelEntryList;
DefineLayerEntry:
PUBLIC
ENTRY
PROC [tech: CD.Technology, lev: CD.Layer, text: Rope.
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;
Caption:
PROC [panel: Panel]
RETURNS [Rope.
ROPE] =
BEGIN
RETURN [Rope.Cat[
IF panel.design.name#NIL THEN panel.design.name ELSE "no name",
" ",
panel.design.technology.name,
" ",
CDCells.PushedCellName[panel.design]
]];
END;
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;
TerminalIO.WriteRope["Create a control panel\n"];
IF panel=
NIL
OR panel.design=
NIL
OR panel.design.technology=
NIL
THEN {
TerminalIO.WriteRope["not registered properly\n"];
ERROR
};
panel.labels ← 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[
boundTo: panel.design, key: $PanelHeight, propagation: global, ifNotFound: 120],
scrollable: TRUE,
iconic: UserProfile.Boolean["ChipNDale.ControlViewerOpenIconic", FALSE],
icon: CDTipEtc.GetPanelIcon[panel.design],
column: right
]];
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 => [] ← CreateLabEntry[panel, labDef];
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.
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,
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.
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,
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.
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,
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.ROPE;
intRef: REF Tripple ← NEW[Tripple ← [panel: panel, define: intDef]];
lambda: INT ← intDef.lambda;
IF lambda<=0 THEN lambda ← panel.design.technology.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: 9];
END;
Tripple: TYPE = RECORD [panel: Panel, define: REF ← NIL, feedback: REF ← NIL];
CreateLabEntry:
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.labels ← CONS[tripple, panel.labels];
RedisplayLabel[tripple];
}
END;
RedisplayLabel:
PROC [tripple:
REF Tripple] =
BEGIN
IF tripple=NIL THEN RETURN;
WITH tripple.define
SELECT
FROM
labDef:
REF LabelDefine => {
x:
REF = CDValue.Fetch[
boundTo: tripple.panel.design,
key: labDef.cdValueKey,
propagation: global
];
Labels.Set[NARROW[tripple.feedback], CDCommandOps.ToRope[x, "-?-"]];
};
butDef:
REF ButtonDefine => {
x:
REF = CDValue.Fetch[
boundTo: tripple.panel.design,
key: butDef.cdValueKey,
propagation: 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.labels, 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: NEW[Tripple ← [panel: panel, define: butDef]]
];
IF butDef.cdValueKey#
NIL
THEN {
tripple: REF Tripple ← NEW[Tripple ← [panel: panel, define: butDef, feedback: but]];
panel.labels ← CONS[tripple, panel.labels];
RedisplayLabel[tripple];
}
END;
ButtonCalled: Buttons.ButtonProc =
BEGIN
tripple: REF Tripple = NARROW[clientData];
butDef: REF ButtonDefine = NARROW[tripple.define];
comm: CDSequencer.Command =
NEW[CDSequencer.CommandRec←[
data: butDef.data,
design: tripple.panel.design
]];
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.
ROPE, lambda:
INT𡤁]
RETURNS [new:
INT] =
BEGIN
ENABLE TerminalIO.UserAbort => GOTO aborted;
choice: LIST OF Rope.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
tripple: REF Tripple = NARROW[clientData];
CDSequencer.ExecuteProc[
proc: SerializedIntCalled,
design: tripple.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;
SerializedIntCalled:
PROC [comm: CDSequencer.Command] =
BEGIN
ENABLE UNWIND => NULL;
i: INT;
tripple: REF Tripple = NARROW[comm.data];
intDef: REF IntDefine = NARROW[tripple.define];
lambda: INT ← intDef.lambda;
IF lambda<=0 THEN lambda ← tripple.panel.design.technology.lambda;
i ← CDValue.FetchInt[
boundTo: tripple.panel.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[
boundTo: tripple.panel.design,
key: intDef.cdValueKey,
value: 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,
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,
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.
ROPE, min:
INT, max:
INT, default:
INT, lambda:
INT] =
BEGIN
ENABLE UNWIND => NULL;
class: PanelClass = GetPanelClass[tech];
def: REF IntDefine = NEW[IntDefine ← [cdValueKey: cdValueKey, text: text, min: min, max: max, default: default, lambda: lambda]];
AppendEntry[class, def];
CDValue.StoreInt[boundTo: tech, key: cdValueKey, value: default];
END;
ContainerDeleted: ViewerEvents.EventProc = {
--break circularities (for garbage collection)
WITH ViewerOps.FetchProp[viewer, $CDPanelPrivate]
SELECT
FROM
panel: Panel => {
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.labels ← NIL;
};
};
ENDCASE => NULL;
};
EnumDesigns:
PROC[p: CDPrivate.DesignEnumerator]
RETURNS [quit:
BOOL←
FALSE] =
BEGIN
FOR list:
LIST
OF Panel ← 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.