<> <> <> <> <<>> 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_1] = 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]; }; END; 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(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] }; GetAnInt: PROC [old, default: INT, label: ROPE, lambda: INT_1] 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; SerializedWireWidthCalled: 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.