CDVCommands.mesa (part of ChipNDale)
Copyright © 1983, 1986, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 29, 1983 4:44 pm
Last Edited by: Christian Jacobi, April 1, 1987 8:05:54 pm PST
Some procedures by: Jean-Marc Frailong, June 3, 1987 12:30:59 pm PDT
DIRECTORY
Atom,
CD,
CDBasics,
CDDefaultProcs,
CDDrawQueue,
CDCells,
CDEnvironment,
CDEvents,
CDInstances,
CDOps,
CDPanel,
CDProperties,
CDSequencer,
CDValue,
CDViewer,
CDViewerBackdoor,
CDViewerInternals,
CDVPrivate,
CDVScale,
Imager,
ImagerSample USING [MapFromFrameBuffer, Move, nullFunction],
InterminalBackdoor USING [terminal],
IO,
PopUpSelection,
Process,
Rope,
SF USING [Vec],
Terminal,
TerminalIO,
UserProfile,
VFonts,
ViewerClasses USING [Viewer],
ViewerOps USING [PaintViewer, GetViewer, SetViewer, OpenIcon, BlinkIcon];
CDVCommands: CEDAR PROGRAM
IMPORTS Atom, CD, CDBasics, CDDefaultProcs, CDDrawQueue, CDCells, CDEnvironment, CDEvents, CDInstances, CDOps, CDPanel, CDProperties, CDSequencer, CDValue, CDViewer, CDViewerBackdoor, CDVPrivate, CDVScale, Imager, ImagerSample, InterminalBackdoor, IO, PopUpSelection, Process, Rope, Terminal, TerminalIO, UserProfile, ViewerOps, VFonts
EXPORTS CDViewerInternals
SHARES CDVPrivate =
BEGIN
VRef: TYPE = CDVPrivate.VRef;
--Utilities and public
DoWithVRef: PROC [comm: CDSequencer.Command, proc: PROC[vRef: VRef]] = {
v: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
IF v=NIL THEN TerminalIO.PutRope["failed: no viewer\n"]
ELSE WITH v.data SELECT FROM
vRef: VRef => IF ~vRef.viewer.destroyed THEN proc[vRef];
ENDCASE => NULL;
};
AddCR: PROC [r: Rope.ROPE] RETURNS [Rope.ROPE] = {
--if r does not already has a CR
ml: INT ← Rope.Length[r];
IF Rope.Fetch[r, ml-1]#'\n THEN RETURN[Rope.Concat[r, "\n"]];
RETURN [r];
};
MsgAndVRef: PROC [comm: CDSequencer.Command, msg: Rope.ROPE] RETURNS [vRef: VRef←NIL] = {
v: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
TerminalIO.PutRope[AddCR[msg]];
IF v=NIL THEN TerminalIO.PutRope[" failed: no viewer\n"]
ELSE WITH v.data SELECT FROM
vr: VRef =>
IF ~vr.viewer.destroyed THEN vRef ← vr
ELSE TerminalIO.PutRope[" failed: viewer destroyed\n"];
ENDCASE => TerminalIO.PutRope[" failed: no ChipNDale viewer\n"];
};
Repaint: PROC [v: REF] = {
WITH v SELECT FROM
vRef: VRef => {
CDDrawQueue.Flush[vRef.ct];
CDDrawQueue.QueueInsertDrawCommand[vRef.ct, CDDrawQueue.Request[$changeScale, CDBasics.universe]];
CDDrawQueue.QueueInsertDrawCommand[vRef.ct, CDDrawQueue.Request[$redraw, CDBasics.universe]];
};
viewer: ViewerClasses.Viewer => Repaint[viewer.data];
comm: CDSequencer.Command => Repaint[comm.ref];
ENDCASE => NULL;
};
SaveScale: PUBLIC PROC [viewer: ViewerClasses.Viewer] = {
IF viewer#NIL THEN
WITH viewer.data SELECT FROM
vRef: VRef => CDProperties.PutProp[vRef.properties, $CDxSavedScale, NEW[CDVScale.ScaleRec ← vRef.scale]];
ENDCASE => NULL;
};
RestoreScale: PUBLIC PROC [viewer: ViewerClasses.Viewer] = {
IF viewer#NIL THEN
WITH viewer.data SELECT FROM
vRef: VRef => {
GetScale: PROC [key: ATOM] RETURNS [CDVScale.ScaleRec] = {
WITH CDProperties.GetProp[vRef.properties, key] SELECT FROM
sr: REF CDVScale.ScaleRec => RETURN [sr^];
ENDCASE => RETURN [CDVScale.MakeScale[]];
};
scale: CDVScale.ScaleRec ← GetScale[$CDxSavedScale];
CDDrawQueue.Flush[vRef.ct];
--NO SaveScale[viewer]; it is better to have one fixed point
IF vRef.scale.off=scale.off AND vRef.scale.nscale=scale.nscale THEN
scale ← GetScale[$CDxSecondaryScale];
CDProperties.PutProp[vRef.properties, $CDxSecondaryScale, NEW[CDVScale.ScaleRec ← vRef.scale]];
vRef.intendedScale ← CDVScale.MakeScale[off: scale.off, nscale: scale.nscale, grid: vRef.scale.grid];
Repaint[vRef];
};
ENDCASE => NULL;
};
WriteLnScale: PROC [v: REF] = {
TerminalIO.PutRope["\n"];
We don't really write the scale number because the scale is changed asynchrounously
and we don't really know when its done.
WITH v SELECT FROM
vRef: VRef => TerminalIO.PutF1[" (scale: %g)\n", IO.int[vRef.scale.nscale]];
viewer: ViewerClasses.Viewer => WriteLnScale[viewer.data];
comm: CDSequencer.Command => WriteLnScale[comm.ref];
ENDCASE => TerminalIO.PutRope["\n"];
};
ChangeScale: PROC [vRef: VRef, newScale: INT] = {
newScale ← MIN[MAX[0, newScale], CDVScale.scaleNum-1];
IF vRef.scale.nscale = newScale THEN
TerminalIO.PutRope["no scale change"]
ELSE {
oldDesignCenterOffset, newDesignCenterOffset: CD.Position;
viewerCenterOffset: CD.Position ← [vRef.viewer.cw/2, vRef.viewer.ch/2];
off: CD.Position ← vRef.scale.off;
dscale: CDVScale.ScaleRec;
CDDrawQueue.Flush[vRef.ct];
TerminalIO.PutRope["change scale"];
dscale ← CDVScale.MakeScale[nscale: vRef.scale.nscale, grid: vRef.scale.grid];
oldDesignCenterOffset ← CDVScale.ViewerToDesignPosition[dscale, viewerCenterOffset];
dscale ← CDVScale.MakeScale[nscale: newScale, grid: vRef.scale.grid];
newDesignCenterOffset ← CDVScale.ViewerToDesignPosition[dscale, viewerCenterOffset];
off ← CDBasics.SubPoints[
CDBasics.AddPoints[off, oldDesignCenterOffset],
newDesignCenterOffset
];
dscale ← CDVScale.MakeScale[off: off, nscale: newScale, grid: vRef.scale.grid];
vRef.intendedScale ← dscale;
Repaint[vRef];
};
WriteLnScale[vRef.viewer];
};
ScaleUp: PROC [comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {
i: INT ← vRef.scale.nscale;
i ← IF i>0 THEN i-1 ELSE 0;
ChangeScale[vRef, i];
};
DoWithVRef[comm, Do]
};
ScaleDown: PROC [comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {ChangeScale[vRef, vRef.scale.nscale+1]};
DoWithVRef[comm, Do]
};
SimpleMoveScreen: PROC [comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {
off: CD.Position;
CDDrawQueue.Flush[vRef.ct];
off.x ← vRef.scale.off.x-(comm.pos.x-comm.sPos.x);
off.y ← vRef.scale.off.y-(comm.pos.y-comm.sPos.y);
vRef.intendedScale ← CDVScale.MakeScale[off: off,nscale: vRef.scale.nscale,grid: vRef.scale.grid];
Repaint[vRef];
};
TerminalIO.PutRope["move window\n"];
DoWithVRef[comm, Do]
};
MoveScreenCmd: PROC [comm: CDSequencer.Command] ~ {
Queue a special paint request as result of the move command. Do NOT flush the queue since display might be uncomplete if repaint is interrupted now.
Do: PROC[vRef: VRef] = {
CDDrawQueue.QueueInsertDrawCommand[vRef.ct, CDDrawQueue.Request[$fastMoveScreen, [x1: comm.pos.x-comm.sPos.x, y1: comm.pos.y-comm.sPos.y, x2: 0, y2: 0]]];
};
TerminalIO.PutRope["move window\n"];
DoWithVRef[comm, Do]
};
GCD: PROC [ m, n: INT ] RETURNS [ INT ] = {
r: INT;
SELECT m FROM
<0 => m ← -m;
ENDCASE => NULL;
SELECT n FROM
<0 => n ← -n;
>0 => NULL;
ENDCASE => RETURN[m];
r ← m MOD n;
WHILE r>0 DO m ← n; n ← r; r ← m MOD n; ENDLOOP;
RETURN[n];
};
DoMoveScreen: CDViewerBackdoor.FurtherPaintProc ~ {
Does the repainting associated to MoveScreenCmd. The algorithm is as follows:
- Flush the queue (required because of ordering problems....)
- Under VRef monitor, do:
- check that the scale did not change and the offset is non-null. Quit if so.
- compute offset in viewer coordinates
- compute area of viewer that is part of the old and new view as the intersection between the viewer's client area and the same offsetted (dstBltRect), translate result back by the offset to get srcBltRect
- Blit the right area (under Terminal lock to suppress cursor if color display)
- Enumerate the rectangles of the viewer client space that need repaint, convert them back conservatively to CD coordinates
- If the move could not be done fast, re-queue a regular redraw (a null move results in a full repaint to undo any wedging that might occur) and return
- Set the new scale in effect
- For each rectangle that needs repaint, erase it and queue a redraw command. The erasing is done first to make the display look cleaner to the user... The rectangles are erased twice, but this is necessary to avoid some wedging (pop out of cell and move fast immediately)
ProtectedAction: PROC [vRef: VRef] ~ {
Contains all the actions that need the VRef to be invariant. This is a conceptually part of the CDVDraw module.
FrameBaseOfViewerRect: PROC [r: CD.Rect] RETURNS [SF.Vec] ~ INLINE {
Convert a rectangle in viewer coordinates to its base in frame coordinates (origin at top...)
RETURN [[
s: vRef.frame.height-vRef.viewer.wy-r.y2,
f: vRef.viewer.wx+r.x1
]];
};
Blit: PROC [] ~ { -- Move bits around
ImagerSample.Move[
map: ImagerSample.MapFromFrameBuffer[vRef.frame],
dstMin: FrameBaseOfViewerRect[dstBltRect],
srcMin: FrameBaseOfViewerRect[srcBltRect],
size: [s: srcBltRect.y2-srcBltRect.y1, f: srcBltRect.x2-srcBltRect.x1],
function: ImagerSample.nullFunction];
};
WillRepaint: PROC [vr: CD.Rect--viewer coordinates--] ~ {
Convert a viewer coordinates rectangle into a design coordinates rectangle guaranteed to be larger when mapped back, and insert it in the repaint list.
toRepaint ← CONS [CD.Rect[
x1: CDVScale.UngriddedViewerToDesignScalar[vRef.intendedScale, vr.x1]+vRef.intendedScale.off.x-1,
y1: CDVScale.UngriddedViewerToDesignScalar[vRef.intendedScale, vr.y1]+vRef.intendedScale.off.y-1,
x2: CDVScale.UngriddedViewerToDesignScalar[vRef.intendedScale, vr.x2]+vRef.intendedScale.off.x+1,
y2: CDVScale.UngriddedViewerToDesignScalar[vRef.intendedScale, vr.y2]+vRef.intendedScale.off.y+1
], toRepaint];
};
clientRect, srcBltRect, dstBltRect: CD.Rect;
offset: CD.Position;
Check that fast redraw is possible and consistent
IF vRef.scale.nscale#vRef.intendedScale.nscale OR vRef.scale.off=vRef.intendedScale.off THEN RETURN; -- do a regular redraw
Compute the correct rectangles for the bit blit
clientRect ← [x1: vRef.viewer.cx, y1: vRef.viewer.cy, x2: vRef.viewer.cx+vRef.viewer.cw, y2: vRef.viewer.cy+vRef.viewer.ch]; -- viewer client rect in viewer coords
offset ← CDVScale.DesignToViewerPosition[vRef.intendedScale, vRef.scale.off];
dstBltRect ← CDBasics.Intersection[clientRect, CDBasics.MoveRect[clientRect, offset]];
srcBltRect ← CDBasics.MoveRect[dstBltRect, CDBasics.NegOffset[offset]];
Do the bit-blit, while removing cursor if on color display
IF vRef.display=bw
THEN Blit[]
ELSE Terminal.ModifyColorFrame[vt: InterminalBackdoor.terminal, action: Blit];
Compute the screen rectangles that need repaint, convert them back to CD coordinates and queue them for execution
CDBasics.DecomposeRect[r: clientRect, test: dstBltRect, outside: WillRepaint];
}; -- End of ProtectedAction
toRepaint: LIST OF CD.Rect ← NIL; -- when NIL, means repaint all, erase and paint each rect
req: REF CDDrawQueue.Request ← NARROW[key];
scale: CDVScale.ScaleRec ← me.scale;
off: CD.Position; mod: CD.Number;
Fix offset to keep stipples matching
mod ← MAX[CDVScale.ViewerToDesignScalar[scale, 4], 1];
IF scale.grid>1 THEN mod ← mod/GCD[mod, scale.grid]*scale.grid;
off ← [scale.off.x-req.rect.x1/mod*mod, scale.off.y-req.rect.y1/mod*mod];
me.intendedScale ← CDVScale.MakeScale[off: off, nscale: scale.nscale, grid: scale.grid];
CDDrawQueue.Flush[me.ct];
CDVPrivate.DoInsideMonitor[ProtectedAction, me];
IF toRepaint=NIL THEN { -- cannot do a fast move, do a repaint and quit.
CDDrawQueue.QueueInsertDrawCommand[me.ct, CDDrawQueue.Request[$changeScale, CDBasics.universe]];
RETURN;
};
Update scale information in all concerned parties...
CDVPrivate.ResetDrawScale[me];
Repaint the missing parts
WHILE toRepaint#NIL DO
CDVPrivate.RepaintBackground[me, toRepaint.first, TRUE]; --immediate
CDDrawQueue.QueueInsertDrawCommand[me.ct, CDDrawQueue.Request[$redraw, toRepaint.first]];--delayed
toRepaint ← toRepaint.rest;
ENDLOOP;
};
GetViewerInt: PROC [viewer: ViewerClasses.Viewer, at: ATOM] RETURNS [i: INT ← -1] = {
WITH ViewerOps.GetViewer[viewer, at] SELECT FROM
ri: REF INT => i ← ri^;
ENDCASE => NULL;
};
GridComm: PROC [comm: CDSequencer.Command] = {
GridRope: PROC [v: ViewerClasses.Viewer] RETURNS [r: Rope.ROPE] = {
r ← CDOps.LambdaRope[GetViewerInt[viewer, $Grid], lambda]
};
g: INT ← -1;
lambda: INT ← comm.design.technology.lambda;
viewer: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
IF viewer=NIL THEN TerminalIO.PutRope["no viewer\n"]
ELSE {
IF comm.key=$GridDouble THEN g ← GetViewerInt[viewer, $Grid]*2
ELSE IF comm.key=$GridHalf THEN g ← GetViewerInt[viewer, $Grid]/2
ELSE {
TerminalIO.PutF1["grid command (current grid = %g)\n", [rope[GridRope[viewer]]]];
SELECT PopUpSelection.Request[
choice: LIST[" 1", " 2", " 4", " 8", "16", "1/2", "default", "type lambda", "type int", "move selected to grid", "TICKS"],
header: "grid",
headerDoc: "grid = distance used for snapping the cursor"] FROM
1 => g ← lambda;
2 => g ← 2*lambda;
3 => g ← 4*lambda;
4 => g ← 8*lambda;
5 => g ← 16*lambda;
6 => g ← lambda/2;
7 => g ← CDValue.FetchInt[boundTo: CDViewer.DesignOf[viewer], key: $CDxInitGrid, propagation: global];
8 => g ← MIN[INT[2600/lambda], TerminalIO.RequestInt["grid: "]]*lambda;
9 => g ← MIN[INT[2600], TerminalIO.RequestInt["grid: "]];
10 => {MoveToGridComm[comm]; RETURN};
11 => {CDSequencer.ExecuteCommand[key: $TicksInfo, comm: comm]; RETURN};
ENDCASE => g ← -1;
};
IF g>0 AND g<=2600 THEN {
ViewerOps.SetViewer[viewer: viewer, data: NEW[INT←g], op: $Grid];
TerminalIO.PutF1[" grid set to %g \n", IO.rope[CDOps.LambdaRope[g, lambda]]];
}
ELSE TerminalIO.PutRope[" failed \n"];
};
};
ChangeGridComm: PROC [comm: CDSequencer.Command] = {
viewer: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
};
SetSimplificationComm: PROC[comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {
n: INT;
CDDrawQueue.Flush[vRef.ct];
n ← PopUpSelection.Request[
choice: LIST["very simplified", "simplified", "standard", "detailed", "very detailed", "show all"],
header: "viewer simplification treshold",
headerDoc: "the viewer simplification treshold is multiplied with the cell simplification treshold"
];
SELECT n FROM
1 => vRef.suppressFactorForCells ← 0.4;
2 => vRef.suppressFactorForCells ← 0.7;
3 => vRef.suppressFactorForCells ← 1;
4 => vRef.suppressFactorForCells ← 1.6;
5 => vRef.suppressFactorForCells ← 2.6;
6 => vRef.suppressFactorForCells ← 0;
ENDCASE => RETURN;
Repaint[vRef]
};
TerminalIO.PutRope["set viewer simplification threshold\n"];
DoWithVRef[comm, Do]
};
InstanceNames: PROC [comm: CDSequencer.Command] = {
v: ViewerClasses.Viewer ~ CDViewer.GetViewer[comm];
TerminalIO.PutRope["display instance names\n"];
IF v#NIL THEN
ViewerOps.PaintViewer[v, client, FALSE, $DrawInstanceNames]
};
SignalNames: PROC [comm: CDSequencer.Command] = {
v: ViewerClasses.Viewer = CDViewer.GetViewer[comm];
TerminalIO.PutRope["display signal names\n"];
IF v#NIL THEN
ViewerOps.PaintViewer[v, client, FALSE, $DrawSignalNames]
};
GetOppositViewer: PROC [comm: CDSequencer.Command] RETURNS [ViewerClasses.Viewer] = {
--gets viewer on different screen if possible,
--else different viewer, if possible...
vl: CDViewer.ViewerList = CDViewer.ViewersOf[comm.design];
viewer: ViewerClasses.Viewer = CDViewer.GetViewer[comm];
onColor: BOOL = (viewer=NIL OR viewer.column=color);
FOR l: CDViewer.ViewerList ← vl, l.rest WHILE l#NIL DO
IF ~l.first.iconic THEN
IF (l.first.column=color)#onColor THEN RETURN [l.first];
ENDLOOP;
FOR l: CDViewer.ViewerList ← vl, l.rest WHILE l#NIL DO
IF ~l.first.iconic THEN
IF l.first.column#viewer.column THEN RETURN [l.first];
ENDLOOP;
FOR l: CDViewer.ViewerList ← vl, l.rest WHILE l#NIL DO
IF ~l.first.iconic THEN
IF l.first#viewer THEN RETURN [l.first];
ENDLOOP;
RETURN [viewer];
};
ShowRectX: PROC [comm: CDSequencer.Command] = {
SmallScale: PROC [comm: CDSequencer.Command] RETURNS [BOOL] = {
min: CD.Number = 30;
RETURN [min>ABS[comm.pos.x-comm.sPos.x] AND min>ABS[comm.pos.y-comm.sPos.y]]
};
viewer: ViewerClasses.Viewer ~ GetOppositViewer[comm];
TerminalIO.PutRope["position a viewer\n"];
IF viewer#NIL THEN
IF SmallScale[comm] THEN CDViewer.ShowPosition[viewer: viewer, pos: comm.sPos]
ELSE CDViewer.ShowAndScale[viewer: viewer, rect: CDBasics.ToRect[comm.pos, comm.sPos]];
};
RestoreViewComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["restore previous scale\n"];
RestoreScale[CDViewer.GetViewer[comm]];
};
ShowRect: PROC [comm: CDSequencer.Command] = {
viewer: ViewerClasses.Viewer ~ CDViewer.GetViewer[comm];
TerminalIO.PutRope["scale viewer"];
SaveScale[viewer];
IF comm.pos=comm.sPos THEN CDViewer.ShowPosition[viewer, comm.pos]
ELSE CDViewer.ShowAndScale[viewer, CDBasics.ToRect[comm.pos, comm.sPos]];
WriteLnScale[viewer];
};
ResetScaleComm: PROC [comm: CDSequencer.Command] = {
ResetScaleAll: PROC [viewer: ViewerClasses.Viewer] = {
b: CD.Rect;
TerminalIO.PutRope["reset scale (view all)"];
b ← CDOps.BoundingBox[CDViewer.DesignOf[viewer]];
IF CDBasics.NonEmpty[b] THEN CDViewer.ShowAndScale[viewer, b];
WriteLnScale[viewer];
};
viewer: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
IF viewer#NIL THEN {
SaveScale[viewer];
ResetScaleAll[viewer];
};
};
ResetScaleToSelectedComm: PROC [comm: CDSequencer.Command] = {
viewer: ViewerClasses.Viewer = CDViewer.GetViewer[comm];
TerminalIO.PutRope["reset scale to selection"];
IF viewer#NIL THEN {
b: CD.Rect ← CDInstances.BoundingRectO[list: CDOps.InstList[comm.design], selectedOnly: TRUE];
IF CDBasics.NonEmpty[b] THEN {
SaveScale[viewer];
CDViewer.ShowAndScale[viewer: viewer, rect: b];
WriteLnScale[viewer];
RETURN;
};
};
TerminalIO.PutRope[" no selection\n"];
};
ResetScaleToPushedComm: PROC [comm: CDSequencer.Command] = {
viewer: ViewerClasses.Viewer = CDViewer.GetViewer[comm];
IF viewer#NIL THEN {
b: CD.Rect;
SaveScale[viewer];
TerminalIO.PutRope["reset scale (to view all of pushed cell)"];
b ← CDInstances.BoundingRectO[list: CDOps.InstList[comm.design], selectedOnly: FALSE];
IF CDBasics.NonEmpty[b] THEN CDViewer.ShowAndScale[viewer, b];
WriteLnScale[viewer];
};
};
ShowViewersComm: PROC [comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {
CDDrawQueue.QueueInsertDrawCommand[vRef.ct, CDDrawQueue.Request[$ShowViewers, CDBasics.universe]];
};
TerminalIO.PutRope["show viewers\n"];
DoWithVRef[comm, Do]
};
SplitViewer: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["split viewer\n"];
[] ← CDViewer.CreateViewer[comm.design, FALSE]
};
SetCellSimplification: PROC [comm: CDSequencer.Command] = {
Do: PROC[vRef: VRef] = {
scale: CDVScale.ScaleRec ← vRef.scale;
FOR l: CD.InstanceList ← CDOps.InstList[comm.design], l.rest WHILE l#NIL DO
IF l.first.selected AND CDCells.IsCell[l.first.ob] THEN {
simplifyOn: CD.Number ← CDVScale.DesignToViewerScalar[scale, l.first.ob.bbox.y2-l.first.ob.bbox.y1];
CDCells.SetSimplificationTreshhold[l.first.ob, simplifyOn, TRUE];
CDOps.RedrawInstance[comm.design, l.first];
};
ENDLOOP;
};
TerminalIO.PutRope["put visibility threshold to current scale\n"];
DoWithVRef[comm, Do]
};
EnforcePanel: PROC [comm: CDSequencer.Command] = {
v: ViewerClasses.Viewer;
TerminalIO.PutRope["enforce a control panel\n"];
v ← CDPanel.Create[comm.design];
IF v#NIL THEN {
IF v.iconic THEN ViewerOps.OpenIcon[v]
ELSE ViewerOps.BlinkIcon[v, 1, 1, 200]
};
};
FontSubstOnComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: substitute tioga fonts"];
IF vRef#NIL THEN {
vRef.fontSubstitution ← TRUE;
CDProperties.PutProp[comm.design, $CDxSubstituteFonts, $TRUE];
Repaint[vRef];
};
};
FontSubstOffComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: don't substitute tioga fonts"];
IF vRef#NIL THEN {
vRef.fontSubstitution ← FALSE;
CDProperties.PutProp[comm.design, $CDxSubstituteFonts, NIL];
Repaint[vRef];
};
};
DrawEnvComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: draw environment of pushed cells"];
IF vRef#NIL THEN {
vRef.environment ← TRUE;
CDProperties.PutProp[comm.design, $CDxDrawEnvironment, NIL];
Repaint[vRef];
};
};
DontDrawEnvComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: don't draw environment of pushed cells"];
IF vRef#NIL THEN {
vRef.environment ← FALSE;
CDProperties.PutProp[comm.design, $CDxDrawEnvironment, $FALSE];
Repaint[vRef];
};
};
DrawSymbolicsComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: draw symbolic objects"];
IF vRef#NIL THEN {
vRef.symbolics ← TRUE;
CDProperties.PutProp[comm.design, $CDxDrawSymbolics, NIL];
Repaint[vRef];
};
};
DontDrawSymbolicsComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: don't draw symbolic objects"];
IF vRef#NIL THEN {
vRef.symbolics ← FALSE;
CDProperties.PutProp[comm.design, $CDxDrawSymbolics, $FALSE];
Repaint[vRef];
};
};
DrawBordersComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: draw with borders"];
IF vRef#NIL THEN {
vRef.borders ← TRUE;
CDProperties.PutProp[comm.design, $CDxSkipBorder, $FALSE];
Repaint[vRef];
};
};
DontDrawBordersComm: PROC [comm: CDSequencer.Command] = {
vRef: VRef ← MsgAndVRef[comm, "viewer drawmode: don't draw borders"];
IF vRef#NIL THEN {
vRef.borders ← FALSE;
CDProperties.PutProp[comm.design, $CDxSkipBorder, NIL];
Repaint[vRef];
};
};
CheckEdited: PROC [design: CD.Design] = {
IF design#NIL THEN {
edited: BOOL ← design.edited;
FOR vl: CDViewer.ViewerList ← CDViewer.ViewersOf[design], vl.rest WHILE vl#NIL DO
IF vl.first.newVersion#edited THEN {
vl.first.newVersion ← edited;
ViewerOps.PaintViewer[vl.first, caption]
};
ENDLOOP
}
};
CheckEditedEvent: CDEvents.EventProc = {
TRUSTED {Process.Detach[FORK CheckEdited[design]]};
};
NoteProfileChange: UserProfile.ProfileChangedProc = {
IF reason=edit THEN {
FOR vl: CDViewer.ViewerList ← CDViewer.ViewersOf[NIL], vl.rest WHILE vl#NIL DO
d: CD.Design ← CDViewer.DesignOf[vl.first];
IF d#NIL THEN vl.first.tipTable ← CDEnvironment.GetTipTable[d];
ENDLOOP
};
};
MoveToGridComm: PROC [comm: CDSequencer.Command] = {
selCnt, movCnt: INT ← 0;
grid: CD.Number ← CDOps.GetGrid[comm.design, comm];
TerminalIO.PutRope["move (interest rect) to grid positions;"];
IF grid<1 THEN {TerminalIO.PutRope["failed: bad grid value"]; RETURN};
FOR l: CD.InstanceList ← CDOps.InstList[comm.design], l.rest WHILE l#NIL DO
IF l.first.selected THEN {
pos: CD.Position ← CDBasics.BaseOfRect[CDInstances.InstRectI[l.first]];
gridded: CD.Position ← [(pos.x)/grid*grid, (pos.y)/grid*grid];
selCnt ← selCnt+1;
IF gridded#pos THEN {
CDSequencer.MarkChanged[comm.design];
CDOps.RedrawInstance[comm.design, l.first];
l.first.trans.off ← CDBasics.AddPoints[l.first.trans.off, CDBasics.SubPoints[gridded, pos]];
CDOps.RedrawInstance[comm.design, l.first, FALSE];
movCnt ← movCnt+1;
};
};
ENDLOOP;
TerminalIO.PutF[" %g selected, %g moved objects\n", [integer[selCnt]], [integer[movCnt]]];
};
ShowViewers: CDViewerBackdoor.FurtherPaintProc = {
--monitored by ProtectedRepaint
OutlineViewer: PROC [me: CDVPrivate.VRef, other: ViewerClasses.Viewer] = {
otherMe: CDVPrivate.VRef = NARROW[other.data];
r: CD.Rect = otherMe.dClip;
p1: CD.Position = CDVScale.DesignToViewerPosition[me.scale, [r.x1, r.y1]];
p2: CD.Position = CDVScale.DesignToViewerPosition[me.scale, [r.x2, r.y2]];
CDVPrivate.InvertArea[me, p1.x, p1.y, p1.x+1, p2.y];
CDVPrivate.InvertArea[me, p1.x, p2.y, p2.x, p2.y+1];
CDVPrivate.InvertArea[me, p2.x, p2.y, p2.x+1, p1.y];
CDVPrivate.InvertArea[me, p2.x, p1.y, p1.x, p1.y+1];
};
FOR l: CDViewer.ViewerList ← CDViewer.ViewersOf[me.actualDesign], l.rest WHILE l#NIL DO
IF ~l.first.iconic AND l.first#me.viewer THEN OutlineViewer[me: me, other: l.first];
ENDLOOP
};
PaintSignalNames: CDViewerBackdoor.FurtherPaintProc = {
--monitored by ProtectedRepaint
PaintProperties[me, $SignalName]
};
PaintInstanceNames: CDViewerBackdoor.FurtherPaintProc = {
--monitored by ProtectedRepaint
PaintProperties[me, $InstanceName]
};
IgnoreContext: CD.DrawContextProc = {};
PaintProperties: PROC [me: CDVPrivate.VRef, key: ATOM] = {
nameDevice: REF NameDevice ← NEW[NameDevice←[propKey: key, vPriv: me]];
internalPr: CD.DrawRef = CD.CreateDrawRef[[
design: me.actualDesign,
interestClip: me.dClip,
devicePrivate: nameDevice,
drawChild: NamedDrawChild,
drawRect: CDDefaultProcs.IgnoreRect,
drawContext: IgnoreContext,
stopFlag: me.stoprequest
]];
Imager.SetColor[me.viewContext, Imager.black];
Imager.SetFont[me.viewContext, defaultFont];
CDOps.DrawDesign[me.actualDesign, internalPr];
};
NameDevice: TYPE = RECORD [propKey: ATOM, vPriv: CDVPrivate.VRef];
defaultFont: Imager.Font = VFonts.DefaultFont[];
NamedDrawChild: CD.DrawProc = {
dev: REF NameDevice = NARROW[pr.devicePrivate];
text: Rope.ROPENIL;
ob.class.drawMe[pr, ob, trans, readOnlyInstProps];
WITH CDProperties.GetListProp[readOnlyInstProps, dev.propKey] SELECT FROM
r: Rope.ROPE => text ← r;
a: ATOM => text ← Atom.GetPName[a];
ENDCASE => NULL;
IF text#NIL THEN {
r: CD.Rect ← CDBasics.MapRect[CD.InterestRect[ob], trans];
p: CD.Position ← CDVScale.DesignToViewerPosition[dev.vPriv.scale, CDBasics.BaseOfRect[r]];
Imager.SetXY[dev.vPriv.viewContext, [p.x+1, p.y+1]];
Imager.SetColor[dev.vPriv.viewContext, Imager.black];
Imager.SetFont[dev.vPriv.viewContext, defaultFont];
Imager.ShowRope[dev.vPriv.viewContext, text];
};
};
DrawSignalNames: CDViewerBackdoor.FurtherPaintProc = {
-- called from anywhere, not monitored
CDDrawQueue.QueueInsertDrawCommand[me.ct, [$SignalNames, CDBasics.universe]];
};
DrawInstanceNames: CDViewerBackdoor.FurtherPaintProc = {
-- called from anywhere, not monitored
CDDrawQueue.QueueInsertDrawCommand[me.ct, [$InstanceNames, CDBasics.universe]];
};
UserProfile.CallWhenProfileChanges[NoteProfileChange];
CDPanel.Button[tech: NIL, button: [text: "stop"], command: $AbortCommand, queue: dontQueue, topLine: TRUE];
CDPanel.Button[tech: NIL, button: [text: "split"], proc: SplitViewer, queue: dontQueue, topLine: TRUE];
CDSequencer.ImplementCommand[$ScaleLessDetail, ScaleDown,, dontQueue];
CDSequencer.ImplementCommand[$ScaleMoreDetail, ScaleUp,, dontQueue];
CDSequencer.ImplementCommand[$MoveScreen, MoveScreenCmd,, dontQueue];
CDSequencer.ImplementCommand[$DisplayNames, SignalNames,, doQueue];
CDSequencer.ImplementCommand[$DisplayInstanceNames, InstanceNames,, doQueue];
CDSequencer.ImplementCommand[$ShowRectX, ShowRectX,, dontQueue];
CDSequencer.ImplementCommand[$ShowRect, ShowRect,, dontQueue];
CDSequencer.ImplementCommand[$ResetScaleAll, ResetScaleComm,, dontQueue];
CDSequencer.ImplementCommand[$ResetScaleTop, ResetScaleToPushedComm,, dontQueue];
CDSequencer.ImplementCommand[$ResetScaleSel, ResetScaleToSelectedComm,, dontQueue];
CDSequencer.ImplementCommand[$DisplayViewers, ShowViewersComm,, doQueue];
CDSequencer.ImplementCommand[$SplitViewer, SplitViewer,, dontQueue];
CDSequencer.ImplementCommand[$GridInfo, GridComm,, doQueue];
CDSequencer.ImplementCommand[$GridDouble, GridComm,, doQueue];
CDSequencer.ImplementCommand[$GridHalf, GridComm,, doQueue];
CDSequencer.ImplementCommand[$SetSimplification, SetSimplificationComm,, dontQueue];
CDSequencer.ImplementCommand[$RestoreScale, RestoreViewComm,, dontQueue];
CDSequencer.ImplementCommand[$SetCellSimplification, SetCellSimplification];
CDSequencer.ImplementCommand[$EnforcePanel, EnforcePanel,, doQueue];
CDSequencer.ImplementCommand[$ViewFSub, FontSubstOnComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewNFSub, FontSubstOffComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewEnv, DrawEnvComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewNEnv, DontDrawEnvComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewSym, DrawSymbolicsComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewNSym, DontDrawSymbolicsComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewBord, DrawBordersComm,, dontQueue];
CDSequencer.ImplementCommand[$ViewNBord, DontDrawBordersComm,, dontQueue];
CDSequencer.ImplementCommand[$MoveToGrid, MoveToGridComm, NIL, doQueue];
CDEvents.RegisterEventProc[event: $AfterOutput, proc: CheckEditedEvent];
CDEvents.RegisterEventProc[event: $CheckEdited, proc: CheckEditedEvent];
--protected procedures
CDViewerBackdoor.InstallFurtherPaint[keyValue: $ShowViewers, proc: ShowViewers];
CDViewerBackdoor.InstallFurtherPaint[keyValue: $SignalNames, proc: PaintSignalNames];
CDViewerBackdoor.InstallFurtherPaint[keyValue: $InstanceNames, proc: PaintInstanceNames];
--unprotected procedures
CDViewerBackdoor.InstallFurtherPaint[keyValue: $DrawSignalNames, proc: DrawSignalNames];
CDViewerBackdoor.InstallFurtherPaint[keyValue: $DrawInstanceNames, proc: DrawInstanceNames];
CDViewerBackdoor.InstallFurtherPaint[keyValue: $fastMoveScreen, proc: DoMoveScreen];
END.