<> <> <<>> DIRECTORY ViewerClasses USING [Viewer], ViewerOps, List USING [AList, PutAssoc, Assoc], MathDisplayExpr, ViewExprOps; ViewExprOpsImpl: CEDAR PROGRAM IMPORTS ViewerOps, MathDisplayExpr, List EXPORTS ViewExprOps ~ BEGIN <> Viewer: TYPE ~ ViewerClasses.Viewer; DisplayExpr: TYPE ~ MathDisplayExpr.DisplayExpr; <> Selection: TYPE ~ REF SelectionRep; SelectionRep: TYPE ~ RECORD [ active: BOOL _ FALSE, -- TRUE iff selection is currently active flavor: ATOM, -- type of selection viewer: Viewer _ NIL, -- viewer containing selection expr: DisplayExpr _ NIL -- selected expression within viewer ]; <> paintQueue: LIST OF Viewer _ NIL; -- list of viewers waiting to be painted GlobalSelections: List.AList _ NIL; -- list of active selections SelectionFlavors: LIST OF ATOM _ NIL; -- list of each flavor in GlobalSelections <> PaintEnqueue: PUBLIC PROC[v: Viewer] ~ { <> <> FOR l: LIST OF Viewer _ paintQueue, l.rest UNTIL l = NIL DO IF v = l.first THEN RETURN; -- don't need to enqueue if already waiting ENDLOOP; <> paintQueue _ CONS[v, paintQueue]; }; PaintDequeue: PUBLIC PROC[v: Viewer] ~ { <> <> <> newQueue: LIST OF Viewer _ NIL; FOR l: LIST OF Viewer _ paintQueue, l.rest UNTIL l = NIL DO IF v # l.first THEN newQueue _ CONS[l.first, newQueue]; ENDLOOP; <> paintQueue _ newQueue; }; FlushPaintQueue: PUBLIC PROC[] ~ { <> <> FOR l: LIST OF Viewer _ paintQueue, l.rest UNTIL l = NIL DO ViewerOps.PaintViewer[l.first, client]; ENDLOOP; paintQueue _ NIL; }; <> noSelection: PUBLIC ERROR = CODE; GetSelection: PUBLIC PROC[flavor: ATOM] RETURNS[Viewer, DisplayExpr] ~ { <> << currently active selection of type flavor. >> << SIGNALS noSelection if no such selection exists.>> <<>> selection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; IF (selection # NIL) AND (selection.active) THEN RETURN[selection.viewer, selection.expr]; ERROR noSelection; -- no active selection of type flavor exists }; Active: PUBLIC PROC[flavor: ATOM] RETURNS[BOOL] ~ { <> << Otherwise returns FALSE.>> selection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; IF (selection # NIL) AND (selection.active) THEN RETURN[TRUE] ELSE RETURN[FALSE]; }; Select: PUBLIC PROC[flavor: ATOM, viewer: Viewer, expr: DisplayExpr] ~ { <> <> << If a previous selection existed, its associated viewer is repainted.>> << If expr is unselectable, primary selection is cleared (and viewer repainted).>> <> oldSelection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; newSelection: Selection _ NEW[SelectionRep _ [active: TRUE, flavor: flavor, viewer: viewer, expr: expr]]; <<*** this is a hack ***>> IF flavor = $primary THEN UnSelect[$keyboard]; <> IF ~expr.Selectable[] THEN newSelection _ NIL; GlobalSelections _ List.PutAssoc[key: flavor, val: newSelection, aList: GlobalSelections]; AddNewFlavor[flavor]; -- update "all flavors" list IF (oldSelection # NIL) AND (oldSelection.active) THEN PaintEnqueue[oldSelection.viewer]; IF newSelection.active THEN PaintEnqueue[newSelection.viewer]; }; UnSelect: PUBLIC PROC[flavor: ATOM] ~ { <> <> << Repaints associated viewer if selection was active.>> <<>> <> oldSelection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; <<*** this is a hack ***>> IF flavor = $primary THEN UnSelect[$keyboard]; <> GlobalSelections _ List.PutAssoc[key: flavor, val: NIL, aList: GlobalSelections]; <> IF (oldSelection # NIL) AND (oldSelection.active) THEN PaintEnqueue[oldSelection.viewer]; }; UnSelectViewer: PUBLIC PROC[v: Viewer] ~ { <> <> <<>> <> viewer: Viewer _ NIL; displayExpr: DisplayExpr _ NIL; FOR flavors: LIST OF ATOM _ SelectionFlavors, flavors.rest UNTIL flavors = NIL DO [viewer, displayExpr] _ GetSelection[flavors.first ! noSelection => {viewer _ NIL; CONTINUE}]; IF v = viewer THEN UnSelect[flavors.first]; ENDLOOP; }; AddNewFlavor: PROC[flavor: ATOM] ~ { <> <> FOR flavors: LIST OF ATOM _ SelectionFlavors, flavors.rest UNTIL flavors = NIL DO IF flavors.first = flavor THEN RETURN; -- already exists in list ENDLOOP; SelectionFlavors _ CONS[flavor, SelectionFlavors]; -- not already in list, so add it }; END. <<>>