<> <> <> <> <> <> DIRECTORY Carets USING [ResumeCarets, SuspendCarets], ColorWorld USING [TurnOffColor, TurnOnColor], Cursors USING [CursorType, GetCursor, SetCursor], Imager USING [black, ClipRectangleI, Color, Context, MaskRectangle, MaskRectangleI, SetColor, white], ImagerOps USING [Color, ColorFromStipple, GraphicsFromImager], InputFocus USING [CaptureButtons, inputEnabled, ReleaseButtons, WindowManagerTIPTable], Interminal USING [terminal], InterminalExtra USING [InsertAction], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuEntry, MenuProc, ReplaceMenuEntry, SetGuarded], MenusPrivate USING [ClearMenu, DrawMenu, HitMenu, MarkMenu], MessageWindow USING [Append, Blink], PrincOpsUtils USING [IsBound], Terminal USING [BlinkBWDisplay], TIPUser USING [TIPScreenCoords, TIPScreenCoordsRec], ViewerClasses USING [Column, ScrollOp, Viewer], ViewerExtras USING [PaintWindow], ViewerMenus USING [Adjust, Close, Color, Destroy, Grow, Left, Right], ViewerOps USING [ChangeColumn, CloseViewer, EnumerateViewers, EnumProc, InitialiseColorPainting, MouseInViewer, PaintViewer, TopViewer], ViewerSpecs USING [captionHeight, scrollBarW, windowBorderSize], WindowManager USING [ScreenPos], WindowManagerPrivate USING []; WindowManagerImpl: CEDAR MONITOR IMPORTS Carets, ColorWorld, Cursors, Imager, ImagerOps, InputFocus, Interminal, InterminalExtra, Menus, MenusPrivate, MessageWindow, PrincOpsUtils, ViewerExtras, ViewerMenus, ViewerOps, Terminal EXPORTS WindowManager, WindowManagerPrivate SHARES InputFocus, Menus, ViewerClasses, ViewerOps = BEGIN OPEN Cursors, ViewerClasses, ViewerSpecs; Zone: TYPE = {none, menu, scroll, caption, client}; trackingState: Zone _ none; CursorZone: PROC [v: Viewer, mousePos: TIPUser.TIPScreenCoords] RETURNS [z: Zone] = { OPEN v; RETURN[SELECT TRUE FROM parent=NIL AND column#static AND mousePos.mouseY IN [wh-captionHeight..wh] => caption, scrollable AND mousePos.mouseX IN [0..scrollBarW] AND mousePos.mouseY IN [0..ch] => scroll, menu#NIL AND mousePos.mouseY IN ((cy-wy)+ch..wh-captionHeight) => menu, ENDCASE => none ] }; ProcessWindowResults: PUBLIC PROC [self: Viewer, input: LIST OF REF ANY] = { <> zone: Zone; newZone: BOOL; shift, control: BOOL _ FALSE; mousePos: TIPUser.TIPScreenCoords; FOR l: LIST OF REF ANY _ input, l.rest UNTIL l = NIL DO WITH l.first SELECT FROM z: ATOM => { OPEN InputFocus; IF newZone THEN SELECT trackingState FROM -- old feedback scroll => {ReleaseButtons[]; RemoveScrollFeedback[]}; menu => {ReleaseButtons[]; MenusPrivate.ClearMenu[feedbackViewer.menu, feedbackViewer]; feedbackViewer _ NIL}; caption => {ReleaseButtons[]; RemoveCaptionFeedback[]}; ENDCASE; IF newZone THEN SELECT zone FROM -- first time stuff scroll => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; PostScrollFeedback[self]}; menu => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; feedbackViewer _ self; SetC[bullseye]}; caption => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable, self]; PostCaptionFeedback[self]; SetC[bullseye]}; ENDCASE => SetC[textPointer]; SELECT trackingState _ zone FROM -- zone specific ops scroll => SELECT z FROM $M => SetC[scrollUpDown]; $RU => HitScroll[self, mousePos.mouseY, up, shift, control]; $RD, $RM => SetC[scrollUp]; $YU => HitScroll[self, mousePos.mouseY, thumb, shift, control]; $YD, $YM => SetC[scrollRight]; $BU => HitScroll[self, mousePos.mouseY, down, shift, control]; $BD, $BM => SetC[scrollDown]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; menu => SELECT z FROM $RU => MenusPrivate.HitMenu[self.menu, self, mousePos, red, shift, control]; $BU => MenusPrivate.HitMenu[self.menu, self, mousePos, blue, shift, control]; $YU => MenusPrivate.HitMenu[self.menu, self, mousePos, yellow, shift, control]; $RM, $BM, $YM => {MenusPrivate.MarkMenu[self.menu, self, mousePos]}; $RD, $BD, $YD => MenusPrivate.MarkMenu[self.menu, self, mousePos]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; caption => SELECT z FROM $RU => MenusPrivate.HitMenu[windowMenu, self, mousePos, red, shift, control]; $BU => MenusPrivate.HitMenu[windowMenu, self, closePos, blue, FALSE, FALSE]; $YU => MenusPrivate.HitMenu[windowMenu, self, growPos, yellow, FALSE, FALSE]; $RM, $RD => MenusPrivate.MarkMenu[windowMenu, self, mousePos]; $BM, $BD => MenusPrivate.MarkMenu[windowMenu, self, closePos]; $YM, $YD => MenusPrivate.MarkMenu[windowMenu, self, growPos]; $Control => control _ TRUE; $Shift => shift _ TRUE; ENDCASE => NULL; ENDCASE; }; z: TIPUser.TIPScreenCoords => { client: BOOL _ FALSE; mousePos _ z; IF mousePos.mouseX = 0 --AND trackingState = scroll-- THEN mousePos.mouseX _ 1; IF trackingState#none THEN [self, client] _ ViewerOps.MouseInViewer[mousePos]; zone _ IF client OR self=NIL THEN none ELSE CursorZone[self, mousePos]; newZone _ trackingState#zone OR (zone=caption AND self#feedbackViewer) OR (zone=scroll AND self#feedbackViewer); }; z: REF CHAR => TRUSTED {Interminal.terminal.BlinkBWDisplay[]}; ENDCASE => NULL; ENDLOOP; }; AlterColumn: PROC [v: Viewer, mx: INTEGER] = { column: ViewerClasses.Column; right: BOOL ~ mx >= v.ww/2; column _ SELECT v.column FROM left => IF right THEN right ELSE IF colorDisplayOn THEN color ELSE right, right => IF ~right THEN left ELSE IF colorDisplayOn THEN color ELSE left, color => IF right THEN right ELSE left, ENDCASE => ERROR; ViewerOps.ChangeColumn[v, column]; }; SetC: PROC [cursor: CursorType] = INLINE {IF waitCount=0 AND GetCursor[]#cursor THEN SetCursor[cursor]}; HitScroll: PROC [v: Viewer, y: LONG INTEGER, op: ScrollOp, shift, control: BOOL] = { RemoveScrollFeedback[]; IF v.parent=NIL OR v.class.coordSys#top THEN y _ v.ch-y; -- client coords IF v.class.scroll#NIL THEN [] _ v.class.scroll[v, op, SELECT op FROM up, down => y, ENDCASE => (100*y)/v.ch, -- percent shift, control]; SetC[scrollUpDown]; -- put the cursor back PostScrollFeedback[v]; }; feedbackViewer: Viewer _ NIL; visible: Imager.Color ~ ImagerOps.ColorFromStipple[122645B]; inVisible: Imager.Color ~ ImagerOps.ColorFromStipple[100040B]; PostScrollFeedback: PROC [v: Viewer] = { top, bottom: INTEGER; action: PROC[context: Imager.Context] ~ { wbs: INTEGER ~ IF v.border THEN windowBorderSize ELSE 0; baseX, baseY: INTEGER ~ wbs; relY1, relY2: INT; -- so won't overflow relY1 _ baseY; relY2 _ (LONG[100-bottom]*v.ch)/100+baseY; Imager.SetColor[context, inVisible]; Imager.MaskRectangle[context, baseX, relY1, scrollBarW, relY2-relY1]; relY1 _ relY2; relY2 _ relY2 + (LONG[bottom-top]*v.ch)/100; Imager.SetColor[context, visible]; Imager.MaskRectangle[context, baseX, relY1, scrollBarW, relY2-relY1]; Imager.SetColor[context, inVisible]; Imager.MaskRectangle[context, baseX, relY2, scrollBarW, baseY+v.ch-relY2]; }; IF feedbackViewer#NIL OR v.class.scroll=NIL THEN RETURN; IF ~v.init THEN RETURN; -- avoid a race condition bug [top, bottom] _ v.class.scroll[v, query, 0]; IF top>100 OR bottom>100 THEN RETURN; Carets.SuspendCarets[]; ViewerExtras.PaintWindow[v, action]; Carets.ResumeCarets[]; feedbackViewer _ v; }; RemoveScrollFeedback: PROC = { v: Viewer ~ feedbackViewer; action: PROC[context: Imager.Context] ~ { wbs: INTEGER ~ IF v.border THEN windowBorderSize ELSE 0; Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, wbs, wbs, scrollBarW, v.ch]; }; IF v=NIL THEN RETURN; Carets.SuspendCarets[]; ViewerExtras.PaintWindow[v, action]; Carets.ResumeCarets[]; feedbackViewer _ NIL; }; DrawCaptionMenu: PUBLIC ENTRY PROC [v: Viewer, guard: BOOL] = {ENABLE UNWIND => NULL; InternalDrawCaptionMenu[v, guard]}; InternalDrawCaptionMenu: INTERNAL PROC [v: Viewer, guard: BOOL] = { OPEN v; action: PROC[context: Imager.Context] ~ { wbs: INTEGER ~ windowBorderSize; Imager.ClipRectangleI[context, wbs, v.wh, v.ww-2*wbs, -captionHeight]; Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, 0, v.wh, v.ww, -captionHeight]; Imager.SetColor[context, Imager.black]; IF guard THEN Menus.SetGuarded[destroyEntry, guardDestroy OR (newVersion AND link=NIL AND ~saveInProgress)]; MenusPrivate.DrawMenu[windowMenu, ImagerOps.GraphicsFromImager[context], wbs, v.wh-captionHeight]; }; IF feedbackViewer#v OR v.iconic OR ~v.visible THEN RETURN; ViewerExtras.PaintWindow[v, action]; }; PostCaptionFeedback: ENTRY PROC [v: Viewer] = { ENABLE UNWIND => NULL; IF feedbackViewer#v THEN { -- remove old IF feedbackViewer#NIL THEN MenusPrivate.ClearMenu[windowMenu, feedbackViewer, FALSE]; feedbackViewer _ v; }; InternalDrawCaptionMenu[v, TRUE]; }; RemoveCaptionFeedback: ENTRY PROC = { ENABLE UNWIND => NULL; IF feedbackViewer#NIL THEN { MenusPrivate.ClearMenu[windowMenu, feedbackViewer, FALSE]; ViewerOps.PaintViewer[feedbackViewer, caption]; feedbackViewer _ NIL; }; }; waitCount: PUBLIC INTEGER _ 0; WaitCursor: PUBLIC ENTRY PROC [cursor: Cursors.CursorType _ hourGlass] = { ENABLE UNWIND => NULL; IF InputFocus.inputEnabled THEN SetCursor[cursor]; waitCount _ waitCount + 1; }; UnWaitCursor: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; waitCount _ MAX[0, waitCount - 1]; IF waitCount=0 THEN RestoreCursor[]; }; RestoreCursor: PUBLIC PROC = TRUSTED {IF InputFocus.inputEnabled THEN InterminalExtra.InsertAction[[contents: deltaMouse[[0,0]]]]}; StartColorViewers: PUBLIC PROC [screenPos: WindowManager.ScreenPos, bitsPerPixel: CARDINAL] = { IF colorDisplayOn THEN StopColorViewers[]; IF PrincOpsUtils.IsBound[ColorWorld.TurnOnColor] THEN colorDisplayOn _ ColorWorld.TurnOnColor[bitsPerPixel, (screenPos=left)] ELSE colorDisplayOn _ FALSE; IF ~colorDisplayOn THEN { MessageWindow.Append["Sorry, you don't have a color display.", TRUE]; MessageWindow.Blink[]; RETURN; }; ViewerOps.InitialiseColorPainting[]; Menus.ReplaceMenuEntry[windowMenu, tNopEntry, tColorEntry]; growPos^ _ [growEntry.xPos+1, FALSE, 0]; closePos^ _ [closeEntry.xPos+1, FALSE, 0]; }; StopColorViewers: PUBLIC PROC = { DoColorViewer: ViewerOps.EnumProc = { IF v.column=color THEN { ViewerOps.CloseViewer[v]; ViewerOps.ChangeColumn[v, left]; }; }; IF ~colorDisplayOn THEN RETURN; ViewerOps.EnumerateViewers[DoColorViewer]; ColorWorld.TurnOffColor[]; colorDisplayOn _ FALSE; Menus.ReplaceMenuEntry[windowMenu, tColorEntry, tNopEntry]; growPos^ _ [growEntry.xPos+1, FALSE, 0]; closePos^ _ [closeEntry.xPos+1, FALSE, 0]; }; BuildWindowMenus: PROC = { windowMenu _ Menus.CreateMenu[]; Menus.AppendMenuEntry[windowMenu, destroyEntry _ Menus.CreateEntry[name: "Destroy", proc: ViewerMenus.Destroy, fork: FALSE, documentation: "Edits will be discarded..."]]; Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Adjust", proc: ViewerMenus.Adjust, fork: FALSE]]; Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Top", proc: Top, fork: FALSE]]; Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "<--", proc: ViewerMenus.Left, fork: FALSE]]; Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "-->", proc: ViewerMenus.Right, fork: FALSE]]; Menus.AppendMenuEntry[windowMenu, tNopEntry _ Menus.CreateEntry["", NIL]]; tColorEntry _ Menus.CreateEntry[name: "Color", proc: ViewerMenus.Color, fork: FALSE]; Menus.AppendMenuEntry[windowMenu, growEntry _ Menus.CreateEntry[name: "Grow", proc: ViewerMenus.Grow, fork: FALSE]]; Menus.AppendMenuEntry[windowMenu, closeEntry _ Menus.CreateEntry[name: "Close", proc: ViewerMenus.Close, fork: FALSE]]; growPos _ NEW[TIPUser.TIPScreenCoordsRec _ [growEntry.xPos+1, FALSE, 0]]; closePos _ NEW[TIPUser.TIPScreenCoordsRec _ [closeEntry.xPos+1, FALSE, 0]]; }; <> Top: Menus.MenuProc = {ViewerOps.TopViewer[NARROW[parent]]}; colorDisplayOn: PUBLIC BOOL _ FALSE; -- color display status windowMenu: PUBLIC Menus.Menu; destroyEntry, closeEntry, growEntry, tColorEntry, tNopEntry: Menus.MenuEntry; growPos, closePos: TIPUser.TIPScreenCoords; BuildWindowMenus[]; END.