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] ~ { 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] ~ { 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] ~ { oldSelection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; newSelection: Selection _ NEW[SelectionRep _ [active: TRUE, flavor: flavor, viewer: viewer, expr: expr]]; 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] ~ { oldSelection: Selection _ NARROW[List.Assoc[key: flavor, aList: GlobalSelections]]; 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. τViewExprOpsImpl.mesa Carl Waldspurger ,August 21, 1986 3:28:21 pm PDT Type Abbreviations From Imported Interfaces Types Global Data (global within this module only) Paint "Queue" Operations modifies: paintQueue effects: If v is not already enqueued, adds v to paintQueue if above loop doesn't return, then we need to add v to queue modifies: paintQueue effects: Removes v from paintQueue. cons up new queue skipping over v make newQueue active modifies: paintQueue effects: Paints each viewer in paintQueue and resets paintQueue (NIL). Selection Operations effects: Returns the viewer and display expression associated with currently active selection of type flavor. SIGNALS noSelection if no such selection exists. effects: Returns TRUE if selection of type flavor is currently active. Otherwise returns FALSE. modifies: GlobalSelections, SelectionFlavors effects: Sets selection flavor to expr in viewer and repaints viewer. If a previous selection existed, its associated viewer is repainted. If expr is unselectable, primary selection is cleared (and viewer repainted). save old selection *** this is a hack *** Point seems to be just that Selecting Primary => UnSelecting KB set new selection if expr is selectable modifies: GlobalSelections effects: UnSelects current selection of type flavor. Repaints associated viewer if selection was active. save old selection *** this is a hack *** Point seems to be just that UnSelecting Primary => UnSelecting KB reset old selection repaint viewer if necessary modifies: GlobalSelections effects: UnSelects all selections associated with viewer v. local declarations modifies: SelectionFlavors effects: SelectionFlavors _ UNION(SelectionFlavors, flavor) Κ˜Jšœ™Jšœ0™0J™codešΟk ˜ Kšœœ ˜Kšœ ˜ Kšœœ˜$K˜K˜ K˜—šΟnœœ˜Jšœ!˜(Jšœ˜—headšž+™+Kšœœ˜$Kšœ œ˜0—šž™Kšœ œœ˜#šœœœ˜KšœœœΟc)˜@KšœœŸ˜#KšœœŸ˜5KšœœŸ$˜=K˜K˜——šž,™,Kšœ œœ œŸ(˜KKšžœœŸ˜AKš žœœœœœŸ*˜Q—šž™šž œ œ˜(Kšœ™Kšœ<™K˜K˜—šžœ œ œ˜'Kšœ™Kšœ4™4Kšœ<™