<> <> <> <> <> <> DIRECTORY Buttons USING [Button, Create], ChoiceButtons USING [BuildTextPrompt, PromptDataRef], Containers USING [Container, Create, ChildXBound, ChildYBound], Environment USING [bytesPerWord], FileIO USING [Open], Graphics, GraphicsOps USING [DrawBitmap, BitmapRep], Icons, IconEditorDefs, IconEditorIO, IO, IconRegistry USING [IsRegistered], Menus USING [ClickProc, Menu, MenuProc], MessageWindow USING [Append, Blink, Confirm], Real USING [FixC], Rope USING [Cat, ROPE, Size], Rules USING [Create], Runtime USING [IsBound], TIPUser USING [TIPScreenCoords, InstantiateNewTIPTable], ViewerClasses USING [DestroyProc, NotifyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass, SetNewVersion], ViewerTools USING [GetContents, SetContents]; IconEditorImplB: CEDAR PROGRAM IMPORTS Buttons, ChoiceButtons, Containers, Graphics, GraphicsOps, Icons, IconEditorDefs, IconEditorIO, IconRegistry, IO, MessageWindow, Real, Rope, Rules, Runtime, TIPUser, ViewerOps, ViewerTools, FileIO EXPORTS IconEditorDefs = { OPEN IconEditorDefs; <<************************** Declarations used for graphics *****************************>> foreground: Graphics.Color _ Graphics.black; background: Graphics.Color _ Graphics.white; deskTopGray: CARDINAL = 122645B; iconEditorIcon: Icons.IconFlavor = Icons.NewIconFromFile["IconEditor.icons", 0]; StartIconEditor: PROC RETURNS [tool: IconHandle] = { ENABLE UNWIND => NULL; iconFileInfo, iconNumberInfo: ChoiceButtons.PromptDataRef; iconFetchButton: Buttons.Button; iconViewerClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: IconPainter, notify: NotifyEvents, destroy: AboutToDestroy, coordSys: bottom, tipTable: TIPUser.InstantiateNewTIPTable["IconEditor.TIP"] ]]; tool _ NEW [IconHandleRec]; tool.iconFileName _ "Sample.icons"; tool.container _ Containers.Create[info: [name: "Icon Editor", scrollable: FALSE, iconic: TRUE, column: left, icon: iconEditorIcon]]; tool.container.menu _ CreateMenu[tool]; iconFileInfo _ ChoiceButtons.BuildTextPrompt[viewer: tool.container, x: 0, y: 0, title: "File: ", textViewerWidth: 250, clientdata: tool]; tool.iconFileWindow _ iconFileInfo.textViewer; ViewerTools.SetContents[tool.iconFileWindow, tool.iconFileName]; iconFileInfo _ ChoiceButtons.BuildTextPrompt[viewer: tool.container, x: iconFileInfo.newx, y: 0, title: " Icon Name: "]; tool.iconNameWindow _ iconFileInfo.textViewer; -- w.t. iconFetchButton _ Buttons.Create[info: [name: "FetchIcon: ", parent: tool.container, wx: 0, wy: 20, border: TRUE], proc: IconFetchProc, clientData: tool, fork: TRUE]; iconNumberInfo _ ChoiceButtons.BuildTextPrompt[viewer: tool.container, x: iconFetchButton.ww, y: 20, title: "Number[0-...]: ", textViewerWidth: 30]; tool.iconNumberWindow _ iconNumberInfo.textViewer; iconFileInfo _ ChoiceButtons.BuildTextPrompt[viewer: tool.container, x: iconNumberInfo.newx, y: 20, title: " from Icon file: "]; tool.iconFetchFileWindow _ iconFileInfo.textViewer; ViewerTools.SetContents[tool.iconFetchFileWindow, tool.iconFileName]; Containers.ChildXBound[tool.container, Rules.Create[info: [parent: tool.container, wx: 0, wy: 40, ww: 1, wh: 1]]]; ViewerOps.RegisterViewerClass[$IconViewer, iconViewerClass]; tool.viewer _ ViewerOps.CreateViewer[flavor: $IconViewer, info: [parent: tool.container, scrollable: FALSE, border: FALSE, wx: 0, wy: 40+distX, data: tool]]; Containers.ChildXBound[tool.container, tool.viewer]; Containers.ChildYBound[tool.container, tool.viewer]; [tool.numberReadIn, tool.iconFile] _ IconEditorDefs.LoadIcons[tool, tool.iconFileName ! IconEditorDefs.CouldntLoadIcons => GOTO BadFile]; tool.numberOfIcons _ tool.numberReadIn; EXITS BadFile => MessageWindow.Append[Rope.Cat["Icon file ",tool.iconFileName," could not be loaded"],TRUE]; }; IconFetchProc: Menus.ClickProc = { OPEN IconEditorDefs; handle: IconHandle _ NARROW[clientData]; badNews: BOOLEAN _ FALSE; iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, icon, handle.currentIC]]; iconNumberRope: Rope.ROPE _ ViewerTools.GetContents[handle.iconNumberWindow]; iconNumber: INTEGER; iconFetchFileName: Rope.ROPE _ ViewerTools.GetContents[handle.iconFetchFileWindow]; h: IO.Handle _ IO.CreateInputStreamFromRope[iconNumberRope]; {ENABLE IO.Error => GOTO BadFile; badNews _ FALSE; iconNumber _ IO.GetInt[h ! IO.Error => { OPEN MessageWindow; Append["Type a valid number in the Number window first!", TRUE]; Blink[]; badNews _ TRUE; CONTINUE }]; IF badNews THEN RETURN; IF Rope.Size[iconNumberRope]=0 OR iconNumber<0 THEN { MessageWindow.Append[message: "Could not fetch icon due to invalid icon number . . .", clearFirst: TRUE]; RETURN}; TRUSTED {-- fetch the icon from the named file fetchFile: IO.Handle _ FileIO.Open[fileName: iconFetchFileName]; numIconsInFile: INTEGER _ fetchFile.GetLength[]/(Environment.bytesPerWord*SIZE[iconFileFormat]); IF iconNumber >= numIconsInFile THEN { MessageWindow.Append[message: "Could not fetch icon due to invalid icon number . . .", clearFirst: TRUE]; RETURN} ELSE { <> <> IO.SetIndex[fetchFile, iconNumber*(Environment.bytesPerWord*SIZE[iconFileFormat])]; <> [] _ IO.UnsafeGetBlock[fetchFile,[LOOPHOLE[handle.icons[LOOPHOLE[handle.currentIC]]], 0, SIZE[iconFileFormat]*2]]; IO.Close[fetchFile]; handle.currentIconRep _ handle.icons[LOOPHOLE[handle.currentIC]]; }; }; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: all, whatChanged: iconInfo, clearClient: FALSE]; EXITS BadFile => MessageWindow.Append[message: Rope.Cat["Icon could not be fetched from ", iconFetchFileName], clearFirst: TRUE]; }}; BitMapToCurrentIcon: PUBLIC PROC [bitmap: REF ANY] = TRUSTED { <> iconInfo: iconInfoRef; handle: IconHandle _ NIL; handle.currentIC _ IconEditorDefs.GetNewFlavor[handle]; handle.currentIconRep _ handle.icons[LOOPHOLE[handle.currentIC]] _ NEW[IconEditorDefs.iconFileFormat]; iconInfo _ NEW[iconInfoRec _ [handle, newIcon, handle.currentIC]]; handle.numberOfIcons _ handle.numberOfIcons + 1; ViewerOps.SetNewVersion[handle.container]; <> handle.icons[LOOPHOLE[handle.currentIC]] _ LOOPHOLE[bitmap]; <> IF LOOPHOLE[handle.currentIC, CARDINAL] >= maxIconsOnDisplay THEN handle.startDisplay _ (handle.startDisplay + 1) MOD handle.numberOfIcons; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client,whatChanged: iconInfo, clearClient: FALSE]; }; UndoProc: PUBLIC Menus.MenuProc = { OPEN IconEditorDefs; handle: IconHandle _ NARROW[clientData]; iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, icon, handle.currentIC]]; ViewerOps.SetNewVersion[handle.container]; Undo[handle, handle.currentIC]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: all, whatChanged: iconInfo, clearClient: FALSE]; }; DeleteIconProc: PUBLIC Menus.MenuProc = { handle: IconHandle _ NARROW[clientData]; iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, screen, handle.currentIC]]; <> IF handle.numberOfIcons < 2 THEN { MessageWindow.Append[message: "Sorry, can't delete the last icon.", clearFirst: TRUE]; MessageWindow.Blink[]; RETURN }; IF ~MessageWindow.Confirm["Confirm deletion of current icon..."] THEN RETURN; DeleteIcon[handle]; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: all, whatChanged: iconInfo, clearClient: FALSE]; }; CleanUp: PROCEDURE [handle: IconHandle, context: Graphics.Context] = { IF handle.functionNotApplied THEN IF handle.drewRectangle THEN {DrawRectangle[handle, context, handle.currentRectangle]; handle.drewRectangle _ FALSE}; IF handle.drewLine THEN {SketchLine[handle, context]; handle.drewLine _ FALSE}; }; IconPainter: PUBLIC ViewerClasses.PaintProc = { ENABLE UNWIND => NULL; iconInfo: iconInfoRef; iconContext: Graphics.Context _ context; bounds: Graphics.Box _ Graphics.GetBounds[iconContext]; MessageWindow.Append[clearFirst: TRUE, message: ""]; IF whatChanged=NIL THEN { <> handle: IconHandle _ NARROW[self.data]; LayoutBoard[handle, bounds ! ViewerNoGood => GOTO Done]; IF ~clear THEN ClearScreen[bounds, iconContext]; DrawIcons[handle, iconContext]; [] _ SetCurrentIcon[handle, XfromIC[handle, handle.currentIC]+10, YfromIC[handle, handle.currentIC]+10]; DrawBoard[handle, iconContext] } ELSE { iconInfo _ NARROW[whatChanged]; IconEditorDefs.LayoutBoard[iconInfo.handle, bounds ! ViewerNoGood => GOTO Done]; SELECT iconInfo.update FROM screen => { ClearScreen[bounds, iconContext]; iconInfo.handle.currentIC _ iconInfo.currentIcon; DrawIcons[iconInfo.handle, iconContext]; [] _ SetCurrentIcon[iconInfo.handle, XfromIC[iconInfo.handle, iconInfo.handle.currentIC]+10, YfromIC[iconInfo.handle, iconInfo.handle.currentIC]+10]; DrawBoard[iconInfo.handle, iconContext]; }; board => DrawBoard[iconInfo.handle, iconContext]; icon => { DrawIcon[iconInfo.handle, iconContext, LOOPHOLE[iconInfo.handle.currentIC _ iconInfo.currentIcon]]; DrawBoard[iconInfo.handle, iconContext] }; bit => { IF iconInfo.clearBit THEN RemoveBit[iconInfo.handle, iconContext, iconInfo.x, iconInfo.y] ELSE AddBit[iconInfo.handle, iconContext, iconInfo.x, iconInfo.y]; }; newIcon => { ClearScreen[bounds, iconContext]; DrawIcons[iconInfo.handle, iconContext]; DrawBoard[iconInfo.handle, iconContext]; DrawBorder[iconInfo.handle, iconContext]; }; mark => { IF iconInfo.handle.firstMark THEN { <> CleanUp[iconInfo.handle, iconContext]; iconInfo.handle.functionNotApplied _ TRUE; [iconInfo.handle.mark1.x, iconInfo.handle.mark1.y] _ BoardCoords[ iconInfo.handle, iconInfo.x, iconInfo.y]; iconInfo.handle.currentRectangle.x _ iconInfo.handle.mark1.x; iconInfo.handle.currentRectangle.y _ iconInfo.handle.mark1.y; iconInfo.handle.currentRectangle.w _ 0; iconInfo.handle.currentRectangle.h _ 0; } ELSE { <> DrawRectangle[iconInfo.handle, iconContext, iconInfo.handle.currentRectangle]; [iconInfo.handle.mark2.x, iconInfo.handle.mark2.y] _ BoardCoords[iconInfo.handle, iconInfo.x, iconInfo.y]; iconInfo.handle.currentRectangle _ IconEditorDefs.NormalizeRectangle[ iconInfo.handle.mark1, iconInfo.handle.mark2]; DrawRectangle[iconInfo.handle, iconContext, iconInfo.handle.currentRectangle]; } }; line => { IF iconInfo.handle.firstMark THEN { <> CleanUp[iconInfo.handle, iconContext]; <> iconInfo.handle.currentRectangle.x _ 0; iconInfo.handle.currentRectangle.y _ 0; iconInfo.handle.currentRectangle.w _ 0; iconInfo.handle.currentRectangle.h _ 0; iconInfo.handle.functionNotApplied _ TRUE; [iconInfo.handle.mark1.x, iconInfo.handle.mark1.y] _ BoardCoords[iconInfo.handle, iconInfo.x, iconInfo.y]; iconInfo.handle.mark2.x _ iconInfo.handle.mark1.x; iconInfo.handle.mark2.y _ iconInfo.handle.mark1.y;-- Initialize the line to be a point iconInfo.handle.currentLine _ IconEditorDefs.TransferEndPoints[iconInfo.handle.mark1, iconInfo.handle.mark2]; } ELSE { <> SketchLine[iconInfo.handle, iconContext]; [iconInfo.handle.mark2.x, iconInfo.handle.mark2.y] _ BoardCoords[iconInfo.handle, iconInfo.x, iconInfo.y]; iconInfo.handle.currentLine _ IconEditorDefs.TransferEndPoints[iconInfo.handle.mark1, iconInfo.handle.mark2]; SketchLine[iconInfo.handle, iconContext]; }; }; rect => { DrawRectangle[iconInfo.handle, iconContext, iconInfo.handle.labelRect]; }; ENDCASE; }; iconContext _ NIL; -- just to be safe EXITS Done => NULL; }; AboutToDestroy: PUBLIC ViewerClasses.DestroyProc = { ENABLE UNWIND => NULL; handle: IconHandle _ NARROW[self.data]; <> <> IO.Close[handle.iconFile]; }; XfromIC: PROC[handle: IconHandle, ic: IconEditorDefs.iconFlavor] RETURNS [CARDINAL] = { i: CARDINAL _ LOOPHOLE[ic]; realFlavor: CARDINAL _ (i - handle.startDisplay + handle.numberOfIcons) MOD handle.numberOfIcons; RETURN [handle.icX+(distX/2) + (realFlavor MOD handle.numIconsPerRow) * (IconEditorDefs.iconW+distX)]; }; YfromIC: PROC[handle: IconHandle, ic: IconEditorDefs.iconFlavor] RETURNS [CARDINAL] = { i: CARDINAL _ LOOPHOLE[ic]; realFlavor: CARDINAL _ (i - handle.startDisplay + handle.numberOfIcons) MOD handle.numberOfIcons; RETURN [handle.icY + (distY/2) + (handle.numIconsPerCol-1-realFlavor / handle.numIconsPerRow) * (IconEditorDefs.iconH+distY)]; }; ICfromXY: PROC[handle: IconHandle, x, y: REAL] RETURNS [ignore: BOOLEAN, ic: IconEditorDefs.iconFlavor] = { xC, yC: CARDINAL; possibleIC, theIC: CARDINAL; iconsOnDisplay: CARDINAL _ MIN[handle.numberOfIcons, maxIconsOnDisplay]; ignore _ FALSE; xC _ Real.FixC[x]; IF xC > handle.icX + (distX/2) THEN xC _ (xC-handle.icX-distX/2)/(IconEditorDefs.iconW+distX) ELSE { ignore _ TRUE; xC _ 0}; yC _ Real.FixC[y]; IF yC > handle.icY + (distY/2) THEN yC _ (yC-handle.icY-distY/2)/(IconEditorDefs.iconH+distY) ELSE { ignore _ TRUE; yC _ 0}; IF xC >= handle.numIconsPerRow THEN xC _ handle.numIconsPerRow-1; IF yC >= handle.numIconsPerCol THEN yC _ handle.numIconsPerCol-1; yC _ handle.numIconsPerCol-1-yC; possibleIC _ handle.numIconsPerRow*yC+xC; -- the icon we might have hit theIC _ (possibleIC + handle.startDisplay) MOD handle.numberOfIcons; ic _ LOOPHOLE[theIC, IconEditorDefs.iconFlavor]; }; BoardCoords: PROC [handle: IconHandle, x, y: REAL] RETURNS [i, j: CARDINAL] = { i _ IF x > handle.boardSize THEN IconEditorDefs.intHBound ELSE Real.FixC[x/handle.unit]; j _ LOOPHOLE[MAX[LOOPHOLE[IconEditorDefs.intHBound-Real.FixC[y/handle.unit],INTEGER], 0]]; }; DeleteIcon: PROCEDURE [handle: IconHandle] = { <> IF LOOPHOLE[handle.currentIC, CARDINAL] < handle.numberOfIcons - 1 THEN { <> FOR i: CARDINAL IN [LOOPHOLE[handle.currentIC, CARDINAL] .. handle.numberOfIcons-1) DO handle.icons[LOOPHOLE[i]] _ handle.icons[LOOPHOLE[i+1]]; ENDLOOP; } ELSE { <> handle.icons[LOOPHOLE[handle.currentIC]] _ NIL; <> <> handle.currentIC _ PRED[handle.currentIC]; }; handle.numberOfIcons _ handle.numberOfIcons - 1; handle.nextFlavor _ PRED[handle.nextFlavor]; handle.currentIconRep _ handle.icons[LOOPHOLE[handle.currentIC]]; }; Undo: PROC [handle: IconHandle, flavor: IconEditorDefs.iconFlavor] = { handle.icons[LOOPHOLE[flavor]].bits _ handle.savedBitMap; }; DrawIcons: PROC [handle: IconHandle, context: Graphics.Context] = { FOR i: CARDINAL IN [0..MIN[handle.numberOfIcons, maxIconsOnDisplay]) DO DrawIcon[handle, context, (handle.startDisplay + i) MOD handle.numberOfIcons]; ENDLOOP; }; DrawBit: PROC [handle: IconHandle, context: Graphics.Context, x, y: CARDINAL] = { OPEN IconEditorDefs; -- for intHBound and unit. lx: REAL _ x*handle.unit; by: REAL _ (intHBound-y)*handle.unit; [] _ Graphics.SetPaintMode[context, invert]; Graphics.DrawBox[context, [xmin: lx+1, ymin: by, xmax: lx+handle.unit, ymax: by+handle.unit-1]]; [] _ Graphics.SetPaintMode[context, opaque]; }; ClearScreen: PROC [bounds: Graphics.Box, context: Graphics.Context] = { p: Graphics.Path _ Graphics.NewPath[5]; Graphics.SetColor[context, background]; Graphics.Rectangle[p, 0.0, 0.0, bounds.xmax, bounds.ymax]; Graphics.DrawArea[context, p]; Graphics.SetColor[context, foreground]; }; DrawBox: PROCEDURE [context: Graphics.Context, x0, y0, x1, y1: INTEGER, thickness: REAL] = { <> p: Graphics.Path _ Graphics.NewPath[5]; [] _ Graphics.SetPaintMode[context, invert]; Graphics.MoveTo[p, x0, y0]; Graphics.LineTo[p, x0, y1]; Graphics.DrawStroke[context, p, normalThickness]; Graphics.FlushPath[p]; Graphics.MoveTo[p, x0 + 1, y1]; Graphics.LineTo[p, x1, y1]; Graphics.DrawStroke[context, p, normalThickness]; Graphics.FlushPath[p]; Graphics.MoveTo[p, x1, y1 - 1]; Graphics.LineTo[p, x1, y0]; Graphics.DrawStroke[context, p, normalThickness]; Graphics.FlushPath[p]; Graphics.MoveTo[p, x1 -1, y0]; Graphics.LineTo[p, x0, y0]; Graphics.DrawStroke[context, p, thickness]; [] _ Graphics.SetPaintMode[context, opaque]; }; DrawIcon: PROC [handle: IconHandle, context: Graphics.Context, index: CARDINAL] = { IF handle.icons[LOOPHOLE[index]] = NIL THEN RETURN -- Just to be safe ELSE { iconBitmap: REF GraphicsOps.BitmapRep _ NEW[GraphicsOps.BitmapRep _ [NIL, IconEditorDefs.iconW/bitsPerWord, IconEditorDefs.iconW, IconEditorDefs.iconH]]; iconBitmap.base _ handle.icons[LOOPHOLE[index]]; Graphics.SetCP[context, XfromIC[handle, LOOPHOLE[index]], YfromIC[handle, LOOPHOLE[index]] + IconEditorDefs.iconH]; GraphicsOps.DrawBitmap[context, iconBitmap, IconEditorDefs.iconW, IconEditorDefs.iconH]; }; }; DrawBoard: PROC [handle: IconHandle, context: Graphics.Context] = { OPEN IconEditorDefs; -- intHBound (to make code less cumbersome) x,y: REAL; [x,y] _ Graphics.GetCP[context]; Graphics.SetColor[context, background]; Graphics.DrawBox[context, [0.0, 0.0, handle.boardSize, handle.boardSize]]; Graphics.SetColor[context, foreground]; FOR i: CARDINAL IN [0..intHBound+1] DO temp: INT; Graphics.SetCP[context, temp _ i*handle.unit, 0.0]; Graphics.DrawTo[context, temp, handle.boardSize]; Graphics.SetCP[context, 0.0, temp _ i*handle.unit]; Graphics.DrawTo[context, handle.boardSize, temp]; ENDLOOP; Graphics.SetCP[context, x, y]; DrawCurrentIcon[handle, context]; handle.drewRectangle _ handle.drewLine _ FALSE; handle.functionNotApplied _ FALSE; }; DrawCurrentIcon: PROC [handle: IconHandle, context: Graphics.Context] = { [] _ Graphics.SetPaintMode[context, invert]; FOR i: CARDINAL IN IconEditorDefs.intH DO FOR j: CARDINAL IN IconEditorDefs.intW DO IF handle.currentIconRep.bits[i].b[j] THEN { lx: REAL _ j*handle.unit; by: REAL _ (IconEditorDefs.intHBound-i)*handle.unit; Graphics.DrawBox[context, [xmin: lx+1, ymin: by, xmax: lx+handle.unit, ymax: by+handle.unit-1]]; }; ENDLOOP; ENDLOOP; [] _ Graphics.SetPaintMode[context, opaque]; }; DrawRectangle: PROC [handle: IconHandle, context: Graphics.Context, rect: IconEditorDefs.rectangleRec] = { <> OPEN IconEditorDefs; -- for unit, intHBound rX0, rY0, rX1, rY1: INTEGER; rX0 _ rect.x*handle.unit - 1; -- top right corner rY0 _ (intHBound-rect.y + 1)*handle.unit + 1; rX1 _ (rect.x + rect.w)*handle.unit + 1; -- bottom left corner rY1 _ (intHBound-rect.y - rect.h + 1)*handle.unit - 1; DrawBox[context, rX0, rY0, rX1, rY1, normalThickness]; handle.drewRectangle _ TRUE; }; DrawBorder: PROC [handle: IconHandle, context: Graphics.Context] = { <> x0, y0, x1, y1: INTEGER; x0 _ XfromIC[handle, handle.currentIC]; y0 _ YfromIC[handle, handle.currentIC]+1; x1 _ x0 + IconEditorDefs.iconW - 1; y1 _ y0 + IconEditorDefs.iconH - 1; DrawBox[context, x0, y0, x1, y1, normalThickness]; }; SketchLine: PROC [handle: IconHandle, context: Graphics.Context] = { <> line: IconEditorDefs.lineRec _ IconEditorDefs.ComputeEndPoints[handle, handle.currentLine]; p: Graphics.Path _ Graphics.NewPath[]; [] _ Graphics. SetPaintMode[context, invert]; Graphics.MoveTo[p, line.x1, line.y1]; Graphics.LineTo[p, line.x2, line.y2]; Graphics.DrawStroke[context, p, normalThickness]; [] _ Graphics.SetPaintMode[context, opaque]; handle.drewLine _ TRUE; }; SetCurrentIcon: PROC [handle: IconHandle, x, y: REAL] RETURNS [ignored: BOOLEAN] = { ic: IconEditorDefs.iconFlavor; [ignored, ic] _ ICfromXY[handle, x, y]; IF ~ignored THEN { handle.currentIC _ ic; handle.currentIconRep _ handle.icons[LOOPHOLE[handle.currentIC]]; } }; BitSet: PROC [handle: IconHandle, x, y: REAL] RETURNS [BOOLEAN] = { xC, yC: CARDINAL; [xC, yC] _ BoardCoords[handle, x, y]; RETURN [handle.currentIconRep.bits[yC].b[xC]]; }; AddBit: PROC [handle: IconHandle, context: Graphics.Context, x, y: REAL] = { xC, yC: CARDINAL; [xC, yC] _ BoardCoords[handle, x, y]; handle.currentIconRep.bits[yC].b[xC] _ TRUE; DrawBit[handle, context, xC, yC]; DrawIcon[handle, context, LOOPHOLE[handle.currentIC]]; }; RemoveBit: PROC [handle: IconHandle, context: Graphics.Context, x, y: REAL] = { xC, yC: CARDINAL; [xC, yC] _ BoardCoords[handle, x, y]; handle.currentIconRep.bits[yC].b[xC] _ FALSE; DrawBit[handle, context, xC, yC]; DrawIcon[handle, context, LOOPHOLE[handle.currentIC]]; }; NotifyEvents: ViewerClasses.NotifyProc = { -- react on user input ENABLE UNWIND => NULL; -- release lock iMouse, jMouse: REAL; erase: BOOLEAN; handle: IconHandle _ NARROW[self.data]; InterpretAtom: PROC [atom: ATOM] = { SELECT atom FROM $Erase => erase _ TRUE; $Select => { IF iMouse > handle.boardSize OR jMouse > handle.boardSize THEN { ignored: BOOLEAN _ SetCurrentIcon[handle, iMouse, jMouse]; IF ~ignored THEN TRUSTED { iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, icon, handle.currentIC]]; IF Runtime.IsBound[IconRegistry.IsRegistered] THEN ViewerTools.SetContents[handle.iconNameWindow, IconRegistry.IsRegistered[ fileName: ViewerTools.GetContents[handle.iconFileWindow], index: LOOPHOLE[handle.currentIC, CARDINAL]].name]; -- w.t. ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: iconInfo, clearClient: FALSE]; }; }; }; $Draw => { -- SetBit / RemoveBit IF iMouse < handle.boardSize AND jMouse < handle.boardSize THEN { ViewerOps.SetNewVersion[handle.container]; IF erase = BitSet[handle, iMouse, jMouse] THEN { iconInfo: iconInfoRef _ NEW[iconInfoRec_[handle, bit, handle.currentIC, erase, iMouse, jMouse]]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: iconInfo, clearClient: FALSE]; }; }; }; $Mark1 => { IF iMouse < handle.boardSize AND jMouse < handle.boardSize THEN { iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, mark, handle.currentIC, erase, iMouse, jMouse]]; handle.firstMark _ TRUE; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: iconInfo, clearClient: FALSE]; }; }; $Mark2 => { IF iMouse < handle.boardSize AND jMouse < handle.boardSize THEN { iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, mark, handle.currentIC, erase, iMouse, jMouse]]; handle.firstMark _ FALSE; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: iconInfo, clearClient: FALSE] }; }; $EndPoint1 => { IF iMouse < handle.boardSize AND jMouse < handle.boardSize THEN { iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, line, handle.currentIC, erase, iMouse, jMouse]]; handle.firstMark _ TRUE; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client,whatChanged: iconInfo, clearClient: FALSE] }; }; $EndPoint2 => { IF iMouse < handle.boardSize AND jMouse < handle.boardSize THEN { iconInfo: iconInfoRef _ NEW[iconInfoRec _ [handle, line, handle.currentIC, erase, iMouse, jMouse]]; handle.firstMark _ FALSE; ViewerOps.SetNewVersion[handle.container]; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: iconInfo, clearClient: FALSE] }; }; ENDCASE; }; -- InterpretAtom FOR params: LIST OF REF ANY _ input, params.rest UNTIL params=NIL DO WITH params.first SELECT FROM x: TIPUser.TIPScreenCoords => { iMouse _ x.mouseX; jMouse _ x.mouseY; erase _ FALSE; }; x: ATOM => InterpretAtom[x]; ENDCASE; ENDLOOP; }; [] _ StartIconEditor[]; }. <> <> <> <<>> <> <> <> <> <> <<>>