<> <> <> <> <<>> DIRECTORY Buttons, CD, CDCellsBackdoor, CDEnvironment, CDEvents, CDLayers, CDOps, CDPanel, CDPrivate, CDSequencer, CDValue, CDViewer, Containers, Labels, Menus, PopUpSelection, Rope, TerminalIO, UserProfile, ViewerEvents, ViewerClasses, ViewerOps, ViewerTools; CDPanelImpl: CEDAR MONITOR IMPORTS Buttons, CD, CDCellsBackdoor, CDEnvironment, CDEvents, CDLayers, CDOps, CDPrivate, CDSequencer, CDValue, CDViewer, Containers, Labels, PopUpSelection, Rope, TerminalIO, UserProfile, ViewerEvents, ViewerOps, ViewerTools EXPORTS CDPanel SHARES CDLayers, CDPrivate = BEGIN <> <> <> <> <> ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; Panel: TYPE = REF PanelRec; -- defines the control panel; one per design PanelRec: TYPE = RECORD [ container: Viewer _ NIL, design: CD.Design, class: Class _ NIL, nextLayerX: CARDINAL _ 0, nextLayerY: CARDINAL _ 0, nextX: CARDINAL _ 0, nextY: CARDINAL _ 0, nextSpecialX: CARDINAL _ 0, layerLabel: Labels.Label _ NIL, layerWidths: LIST OF Actual _ NIL, actuals: LIST OF Actual _ NIL ]; PanelList: TYPE = LIST OF Panel; EntryClass: TYPE = REF EntryClassRec; --class of entry in viewer EntryClassRec: TYPE = RECORD [ build: BuildProc, toDisplay: ToDisplayProc _ NIL, fromdisplay: FromDisplayProc _ NIL, --if defaulted uses cdvalue classData: REF _ NIL ]; BuildProc: TYPE = PROC [panel: Panel, entry: EntryDef]; --builds an entry into a viewer ToDisplayProc: TYPE = PROC [actual: Actual, value: REF]; FromDisplayProc: TYPE = PROC [actual: Actual] RETURNS [value: REF_NIL]; EntryDef: TYPE = REF EntryDefRec; --defines an entry EntryDefRec: TYPE = RECORD [ entryClass: EntryClass, text: ROPE _ NIL, redisplay: BOOL _ TRUE, cdValueKey: REF _ NIL, min, max, default, lambda: INT _ 1, width: INT _ -1, --viewer units layer: CD.Layer _ CD.undefLayer, proc: CDSequencer.CommandProc _ NIL, command: ATOM _ NIL, queue: CDSequencer.QueueMethod _ useDefault, topLine: BOOL _ FALSE, border: BOOL _ FALSE, editable: BOOL _ FALSE, data: REF _ NIL ]; EntryList: TYPE = LIST OF EntryDef; Class: TYPE = REF EntryList; -- one per Technology Actual: TYPE = REF ActualRec; --type used for clientData field of viewer stuff ActualRec: TYPE = RECORD [ panel: Panel, define: EntryDef, feedback: Viewer _ NIL --might be a different viewer doing feedback for the caller ]; panelKey: REF ATOM ~ NEW[ATOM_$Panel]; -- used instead of atoms, to be really unique classKey: REF ATOM ~ NEW[ATOM_$PanelClass]; globalClass: Class ~ NEW[EntryList_NIL]; panelList: PanelList _ NIL; layerDefs: REF ARRAY [0..CD.layerNum) OF EntryDef ~ NEW[ARRAY [0..CD.layerNum) OF EntryDef _ ALL[NIL]]; newLineClass: EntryClass _ RegisterEntryClass[[ build: BuildNewLine ]]; buttonClass: EntryClass _ RegisterEntryClass[[ build: BuildButton, toDisplay: ToDisplayButton ]]; labelClass: EntryClass _ RegisterEntryClass[[ build: BuildLabel, toDisplay: ToDisplayLabel ]]; textClass: EntryClass _ RegisterEntryClass[[ build: BuildText, toDisplay: ToDisplayText, fromdisplay: FromDisplayText ]]; layerClass: EntryClass _ RegisterEntryClass[[ build: BuildLayer ]]; intClass: EntryClass _ RegisterEntryClass[[ build: BuildInt, toDisplay: ToDisplayInt ]]; <<--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; <<-- Viewer>> topY: CARDINAL = 1; entryHSpace: CARDINAL = 3; entryHeight: CARDINAL = 12; shorterEntryVSpace: CARDINAL = 1; RegisterEntryClass: PROC [c: EntryClassRec] RETURNS [entryClass: EntryClass] = { entryClass _NEW[EntryClassRec_c] }; GetPanel: PROC [design: CD.Design] RETURNS [Panel] = { x: REF _ CDValue.Fetch[boundTo: design, key: panelKey, propagation: global]; IF x=NIL THEN { panel: Panel = NEW[PanelRec_[ design: design, class: GetClass[design.technology] ]]; [] _ CDValue.StoreConditional[design, panelKey, panel]; RETURN [GetPanel[design]] }; RETURN [NARROW[x, Panel]]; }; GetClass: PROC [tech: CD.Technology] RETURNS [Class] = { IF tech=NIL THEN RETURN [globalClass] ELSE { x: REF _ CDValue.Fetch[boundTo: tech, key: classKey, propagation: technology]; IF x=NIL THEN { class: Class = NEW[EntryList_NIL]; IF CDValue.StoreConditional[tech, classKey, class] THEN CDLayers.SetCurrentLayer[tech, CD.commentLayer]; RETURN [GetClass[tech]]; }; RETURN [NARROW[x, Class]]; } }; 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>> ENABLE UNWIND => NULL; panel: Panel _ GetPanel[design]; class: Class _ GetClass[design.technology]; IF panel.container#NIL AND NOT panel.container.destroyed THEN RETURN [panel.container]; panel.container _ NIL; panel.actuals _ NIL; <<--supress creation of viewer if empty>> IF class#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] }; CheckPanelList: INTERNAL PROC [p: Panel] = { <<--Get rid of panels which are not used anymore >> <<--No user visible action >> 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 }; BuildEntry: INTERNAL PROC[panel: Panel, entry: EntryDef] = { IF panel.container.destroyed THEN RETURN; entry.entryClass.build[panel, entry]; }; DefineEntry: INTERNAL PROC [tech: CD.Technology, entryRec: EntryDefRec] RETURNS [entry: EntryDef] = { IncludeEntryInClass: INTERNAL PROC [class: Class, entry: EntryDef] = { IF class^=NIL THEN class^ _ LIST[entry] ELSE FOR list: EntryList _ class^, list.rest DO IF list.rest = NIL THEN {list.rest _ LIST[entry]; EXIT} ENDLOOP; }; CreateEntryInViewers: INTERNAL PROC [class: Class, entry: EntryDef] = { 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 BuildEntry[list.first, entry]; } ENDLOOP }; class: Class = GetClass[tech]; entry _ NEW[EntryDefRec_entryRec]; IncludeEntryInClass[class, entry]; CreateEntryInViewers[class, entry]; }; <<-- Define's ===========================================================>> DefineNewLine: PUBLIC ENTRY PROC [tech: CD.Technology] = { ENABLE UNWIND => NULL; [] _ DefineEntry[tech, [entryClass: newLineClass]]; }; 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, redisplay: BOOL] = { ENABLE UNWIND => NULL; IF command=NIL AND queue=useDefault THEN queue _ doQueue; [] _ DefineEntry[tech, [ entryClass: buttonClass, text: name, proc: proc, command: command, queue: queue, data: data, border: border, topLine: topLine, cdValueKey: cdValueKey ]]; }; DefineLabel: PUBLIC ENTRY PROC [tech: CD.Technology_NIL, name: ROPE, border: BOOL _ FALSE, cdValueKey: REF _ NIL, redisplay: BOOL _ TRUE] = { ENABLE UNWIND => NULL; [] _ DefineEntry[tech, [ entryClass: labelClass, text: name, border: border, cdValueKey: cdValueKey ]]; }; DefineLayerEntry: PUBLIC ENTRY PROC [tech: CD.Technology, layer: CD.Layer, text: ROPE, min, default: CD.Number_1] = { ENABLE UNWIND => NULL; IF layer=CD.undefLayer THEN RETURN WITH ERROR CD.Error[callingError]; IF layerDefs[layer]#NIL THEN RETURN WITH ERROR CD.Error[doubleRegistration, "re-registers layer"]; layerDefs[layer] _ DefineEntry[tech, [ entryClass: layerClass, layer: layer, text: text, min: min, default: default ]]; CDLayers.SetLayerWidth[design: NIL --!!! it sets default--, layer: layer, width: default]; }; DefineIntEntry: PUBLIC ENTRY PROC [tech: CD.Technology, cdValueKey: REF, text: ROPE, min: INT, max: INT, default: INT, lambda: INT, redisplay: BOOL] = { ENABLE UNWIND => NULL; CDValue.StoreInt[boundTo: tech, key: cdValueKey, value: default]; [] _ DefineEntry[tech, [ entryClass: intClass, cdValueKey: cdValueKey, text: text, min: min, max: max, default: default, lambda: lambda ]]; }; DefineRopeEntry: PUBLIC ENTRY PROC [tech: CD.Technology _ NIL, cdValueKey: REF, button: Rope.ROPE, width: INT, editable: BOOL, redisplay: BOOL] = { ENABLE UNWIND => NULL; [] _ DefineEntry[tech, [ entryClass: textClass, cdValueKey: cdValueKey, width: width, border: FALSE, text: button, editable: editable ]]; }; <<>> <<-- special treatment for layers ===========================================================>> LayerName: PROC [layer: CD.Layer] RETURNS [r: ROPE] = { IF layerDefs[layer]#NIL THEN RETURN[layerDefs[layer].text] ELSE { r _ CDOps.LayerRope[layer]; IF Rope.IsEmpty[r] THEN r _ "not defined" } }; NotifyCurrentLayer: CDLayers.DesignNotifyProc = { panel: Panel = GetPanel[design]; IF panel.layerLabel#NIL THEN { l: CD.Layer _ CDLayers.CurrentLayer[design]; Labels.Set[panel.layerLabel, LayerName[l]]; } }; NotifyLayerWidth: CDLayers.LayerNotifyProc = { panel: Panel = GetPanel[design]; IF panel.layerLabel#NIL THEN { FOR list: LIST OF Actual _ panel.layerWidths, list.rest WHILE list#NIL DO IF list.first.define.layer=layer THEN { Labels.Set[list.first.feedback, CDOps.LambdaRope[ n: CDLayers.LayerWidth[design, layer], lambda: design.technology.lambda ] ]; EXIT; }; ENDLOOP; } }; <<>> <<-- Viewer Stuff -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->> 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, " ", CDCellsBackdoor.PushedCellName[panel.design] ]]; }; CreatePanelViewer: INTERNAL PROC [panel: Panel] = { MakeClassEntries: INTERNAL PROC [class: Class] = { <<--uses intermediate layer variables!>> FOR l: EntryList _ class^, l.rest WHILE l#NIL DO BuildEntry[panel, l.first]; ENDLOOP; }; IF panel=NIL OR panel.design=NIL OR panel.design.technology=NIL THEN ERROR; TerminalIO.PutRopes["create control panel for ", DesignName[panel.design], "\n"]; panel.actuals _ 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: LayerName[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]; }; RepaintCaptions: CDEvents.EventProc = { panel: Panel _ GetPanel[design]; IF panel.container#NIL THEN { panel.container.name _ Caption[panel]; ViewerOps.PaintViewer[panel.container, caption]; }; }; NextIntButton: PROC [panel: Panel, label: ROPE, proc: Buttons.ButtonProc, border: BOOL _ FALSE, clientData: REF ANY _ NIL] = { 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; }; NextButton: INTERNAL PROC [panel: Panel, label: ROPE, proc: Buttons.ButtonProc, clientData: REF ANY _ NIL, topLine: BOOL _ FALSE, border: BOOL _ FALSE] RETURNS [button: Buttons.Button] = { 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 }; NextLabel: PROC [panel: Panel, name: ROPE, border: BOOL _ FALSE, extraSpaces: CARDINAL _ 0, extraWidth: CARDINAL _ 0] RETURNS [Labels.Label] = { 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] }; BuildInt: BuildProc = { initialValue: ROPE; actual: Actual _ NEW[ActualRec _ [panel: panel, define: entry]]; [] _ NextIntButton[panel: panel, label: entry.text, proc: IntCalled, clientData: actual]; initialValue _ CDOps.LambdaRope[ n: CDValue.FetchInt[panel.design, entry.cdValueKey, technology, entry.default], lambda: ActualLambda[actual] ]; actual.feedback _ NextLabel[panel: panel, name: initialValue, extraWidth: 8]; panel.actuals _ CONS[actual, panel.actuals]; }; ActualLambda: PROC [actual: Actual] RETURNS [lambda: INT] = { lambda _ actual.define.lambda; IF lambda<=0 THEN lambda _ actual.panel.design.technology.lambda }; ToDisplayInt: ToDisplayProc = { n: INT; lambda: INT _ ActualLambda[actual]; WITH value SELECT FROM ri: REF INT => n _ ri^ ENDCASE => n _ actual.define.default; Buttons.ReLabel[actual.feedback, CDOps.LambdaRope[n, lambda]]; }; BuildLabel: BuildProc = { actual: Actual_NIL; lab: Labels.Label _ NextLabel[ panel: panel, name: entry.text, border: entry.border ]; IF entry.cdValueKey#NIL THEN { actual _ NEW[ActualRec _ [panel: panel, define: entry, feedback: lab ]]; panel.actuals _ CONS[actual, panel.actuals]; RedisplayEntry[actual]; } }; ToDisplayLabel: ToDisplayProc = { Labels.Set[actual.feedback, CDOps.ToRope[value, "-?-"]]; }; FetchRopeWithList: PROC [from: REF, key: REF, start: ROPE_NIL] RETURNS [ROPE] = { 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] }; 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 actual.feedback>> actual: Actual _ NARROW[clientData]; selection: REF ViewerTools.SelPosRec _ NIL; v: Viewer _ actual.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 _ FetchRopeWithList[actual.panel.design.technology, actual.define.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 actual.feedback>> FetchSimpleRope: 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]; }; contents, start: ROPE; actual: Actual _ NARROW[clientData]; cdValueKey: REF _ actual.define.cdValueKey; start _ FetchSimpleRope[actual.panel.design, cdValueKey]; contents _ FetchRopeWithList[actual.panel.design.technology, cdValueKey, start]; CDValue.Store[actual.panel.design, cdValueKey, contents]; Labels.Set[actual.feedback, contents]; }; BuildText: BuildProc = { actual: Actual_NEW[ActualRec _ [panel: panel, define: entry, feedback: NIL]]; yoff: INT = Containers.ScrollOffset[panel.container]; w: INT _ IF entry.width<=0 THEN 2000 ELSE MIN[entry.width, 2000]; h: INT _ entryHeight; y: INT _ panel.nextY+yoff; x: INT _ panel.nextX; v: Viewer; IF ~Rope.IsEmpty[entry.text] THEN { button: Buttons.Button _ Buttons.Create[ info: [ name: entry.text, wx: x, wy: y+butYCompensation, wh: h, border: FALSE, parent: panel.container ], clientData: actual, proc: IF entry.editable THEN TextButProc ELSE TextLabButProc ]; x _ button.wx+button.ww+entryHSpace; }; IF entry.editable THEN v _ actual.feedback _ ViewerTools.MakeNewTextViewer[info: [ wx: x, wy: y+textYCompensation, ww: w, wh: h+textHCompensation, parent: panel.container, border: FALSE, data: FetchRopeWithList[panel.design, entry.cdValueKey] ]] ELSE v _ actual.feedback _ Labels.Create[info: [ name: FetchRopeWithList[panel.design, entry.cdValueKey], wx: x, wy: y+labelYCompensation, ww: w, wh: h, parent: panel.container, border: FALSE ]]; panel.nextX _ v.wx+w+entryHSpace; IF entry.width<=0 THEN Containers.ChildXBound[panel.container, v]; panel.actuals _ CONS[actual, panel.actuals]; }; ToDisplayText: ToDisplayProc = { entry: EntryDef _ actual.define; design: CD.Design _ actual.panel.design; rope: ROPE _ CDOps.ToRope[value, " "]; v: Viewer _ actual.feedback; IF v.class.flavor=$Label THEN Labels.Set[v, rope] ELSE ViewerTools.SetContents[v, rope]; }; FromDisplayText: FromDisplayProc = { RETURN [ViewerTools.GetContents[NARROW[actual.feedback]]]; }; <<>> <<-- ================================================>> RedisplayEntry: PROC [actual: Actual] = { IF actual.define.cdValueKey#NIL THEN DoToDisplay[actual, CDValue.Fetch[actual.panel.design, actual.define.cdValueKey, global]] }; DoToDisplay: PROC [actual: Actual, x: REF] = { IF actual.define.entryClass.toDisplay#NIL THEN actual.define.entryClass.toDisplay[actual, x]; }; Redisplay: PUBLIC PROC [design: CD.Design] = { panel: Panel = GetPanel[design]; IF panel.container=NIL OR panel.container.destroyed THEN RETURN; FOR list: LIST OF Actual _ panel.actuals, list.rest WHILE list#NIL DO IF list.first.define.redisplay THEN RedisplayEntry[list.first]; ENDLOOP; }; BuildButton: INTERNAL PROC [panel: Panel, entry: EntryDef] = { but: Buttons.Button = NextButton[ panel: panel, label: entry.text, proc: ButtonCalled, border: entry.border, topLine: entry.topLine, clientData: entry ]; IF entry.cdValueKey#NIL THEN { actual: Actual _ NEW[ActualRec _ [panel: panel, define: entry, feedback: but]]; panel.actuals _ CONS[actual, panel.actuals]; RedisplayEntry[actual]; } }; ToDisplayButton: ToDisplayProc = { Buttons.ReLabel[actual.feedback, CDOps.ToRope[value, "-?-"]]; }; ButtonCalled: Buttons.ButtonProc = { butDef: EntryDef = 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]; }; GetAnInt: PROC [old, default: INT, label: ROPE, lambda: INT_1] RETURNS [new: INT] = { 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", Rope.Concat["type * ", CDOps.LambdaRope[1, lambda]], "trunc"]; SELECT PopUpSelection.Request[header: 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[Rope.Cat["type value ", CDOps.LambdaRope[1, lambda], " > "]]; 8 => new _ old/lambda*lambda; ENDCASE => TerminalIO.PutRope["Skipped\n"]; EXITS aborted => NULL; }; IntCalled: Buttons.ButtonProc = { 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 ]] ]; }; SerializedIntCalled: PROC [comm: CDSequencer.Command] = { ENABLE UNWIND => NULL; design: CD.Design ~ comm.design; actual: Actual ~ NARROW[comm.data]; intDef: EntryDef ~ actual.define; lambda: INT _ ActualLambda[actual]; i: INT _ CDValue.FetchInt[design, intDef.cdValueKey, global, intDef.default]; SELECT TRUE FROM comm.b => { IF comm.n=1 THEN i _ i/lambda*lambda ELSE i _ GetAnInt[i, intDef.default, intDef.text, lambda] }; comm.key=$right => { IF comm.n=1 THEN i_i/2 ELSE i _ Dec[i, lambda] }; comm.key=$left => { IF comm.n=1 THEN i _ Double[i] ELSE i _ Inc[i, lambda] }; ENDCASE => NULL; i _ MAX[MIN[i, intDef.max], intDef.min]; CDValue.StoreInt[design, intDef.cdValueKey, i]; Labels.Set[actual.feedback, CDOps.LambdaRope[n: i, lambda: lambda]]; }; BuildNewLine: BuildProc = { panel.nextY _ panel.nextY+entryHSpace+entryHeight; panel.nextX _ 0; }; BuildLayer: BuildProc = { yoff: INT = Containers.ScrollOffset[panel.container]; p: Actual _ NEW[ActualRec _ [define: entry, panel: panel]]; button: Buttons.Button = Buttons.Create[ info: [ name: entry.text, wx: panel.nextLayerX, wy: panel.nextLayerY+yoff+butYCompensation, wh: entryHeight, parent: panel.container, border: FALSE ], clientData: p, proc: WireWidthCalled ]; p.feedback _ 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: CDOps.LambdaRope[ n: CDLayers.LayerWidth[panel.design, entry.layer], lambda: panel.design.technology.lambda ] ] ]; panel.nextLayerX _ button.wx+button.ww+2*entryHSpace; panel.layerWidths _ CONS[p, panel.layerWidths]; }; WireWidthCalled: Buttons.ButtonProc = { wireRef: Actual = 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 ]] ]; }; SerializedWireWidthCalled: PROC[comm: CDSequencer.Command] = { wireRef: Actual = NARROW[comm.data]; layer: CD.Layer = wireRef.define.layer; design: CD.Design _ wireRef.panel.design; width: CD.Number _ CDLayers.LayerWidth[design, layer]; lambda: INT _ design.technology.lambda; IF comm.b THEN { IF comm.n=1 THEN width _ width/lambda*lambda ELSE width _ GetAnInt[width, wireRef.define.default, wireRef.define.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, layer]; RETURN }; CDLayers.SetLayerWidth[design, layer, MAX[width, 0]]; }; DoFromDisplay: PROC [actual: Actual] RETURNS [x: REF] = { RETURN [ IF actual.define.entryClass.fromdisplay=NIL THEN CDValue.Fetch[actual.panel.design, actual.define.cdValueKey, global] ELSE actual.define.entryClass.fromdisplay[actual] ] }; FromDisplayNoStore: PROC [design: CD.Design, cdValueKey: REF] RETURNS [REF_NIL] = { panel: Panel = GetPanel[design]; FOR list: LIST OF Actual _ panel.actuals, list.rest WHILE list#NIL DO IF list.first.define.cdValueKey=cdValueKey THEN RETURN [DoFromDisplay[list.first]] ENDLOOP; }; FromDisplay: PUBLIC PROC [design: CD.Design, cdValueKey: REF] RETURNS [x: REF] = { x _ FromDisplayNoStore[design, cdValueKey]; CDValue.Store[design, cdValueKey, x]; }; FromDisplayRope: PUBLIC PROC [design: CD.Design, cdValueKey: REF] RETURNS [Rope.ROPE] = { WITH FromDisplay[design, cdValueKey] SELECT FROM r: Rope.ROPE => RETURN [r]; ENDCASE => RETURN [NIL]; }; ToDisplayNoFetch: PROC [design: CD.Design, cdValueKey: REF, value: REF] = { panel: Panel = GetPanel[design]; IF panel.container=NIL OR panel.container.destroyed THEN RETURN; FOR list: LIST OF Actual _ panel.actuals, list.rest WHILE list#NIL DO IF list.first.define.cdValueKey=cdValueKey THEN { DoToDisplay[list.first, value]; } ENDLOOP; }; ToDisplayRope: PUBLIC PROC [design: CD.Design, cdValueKey: REF, rope: Rope.ROPE] = { CDValue.Store[design, cdValueKey, rope]; ToDisplayNoFetch[design, cdValueKey, rope]; }; ToDisplay: PUBLIC PROC [design: CD.Design, cdValueKey: REF] RETURNS [REF_NIL] = { value: REF _ CDValue.Fetch[design, cdValueKey, global]; ToDisplayNoFetch[design, cdValueKey, value]; RETURN [value] }; ContainerDeleted: ViewerEvents.EventProc = { <<--break circularities>> 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.actuals _ NIL; }; }; ENDCASE => NULL; }; <<>> EnumDesigns: PROC[p: CDPrivate.DesignEnumerator] RETURNS [quit: BOOL_FALSE] = { 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; }; <<>> <<--vanilla utilities ================================>> Double: PROC[i: INT] RETURNS [INT] = INLINE { IF i(FIRST[INT]/2) THEN i _ i+i; RETURN [i] }; Inc: PROC[i: INT, x: INT_1] RETURNS [INT] = INLINE { IF i<=LAST[INT]-x THEN i _ i+x; RETURN [i] }; Dec: PROC[i: INT, x: INT_1] RETURNS [INT] = INLINE { IF i>=FIRST[INT]+x THEN i _ i-x; RETURN [i] }; <<>> <<--module initialization ================================>> [] _ CDValue.RegisterKey[panelKey, NIL]; [] _ CDValue.RegisterKey[classKey, 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.