DIRECTORY Basics USING [bitsPerWord, bytesPerWord], Buttons USING [Button], ChoiceButtons USING [BuildTextPrompt, PromptDataRef], Commander USING [CommandProc, Register], CommandTool USING [CurrentWorkingDirectory], Containers USING [Container, Create, ChildXBound, ChildYBound], FS USING [StreamOpen, Error], IconEditorDefs, IconRegistry USING [IsRegistered], Icons USING [IconFlavor, NewIconFromFile], Imager USING [black, Box, Context, DoSave, DoSaveAll, MaskBox, MaskRectangleI, MaskStroke, Rectangle, SetColor, SetStrokeWidth, white], ImagerBackdoor USING [GetBounds, invert, DrawBits], ImagerColorDefs USING [ConstantColor], ImagerPath USING [PathProc], IO USING [Close, EndOfStream, Error, GetInt, GetLength, RIS, SetIndex, STREAM, UnsafeGetBlock], LFBoundingBox USING [GetArea], MBQueue USING [Queue, Create, CreateButton], Menus USING [ClickProc, Menu, MenuProc], MessageWindow USING [Append, Blink, Confirm], PrincOps USING [BBptr, BBTableSpace], PrincOpsUtils USING [AlignedBBTable, BITBLT, IsBound], Real USING [FixC, FixI], Rope USING [Cat, ROPE, Size], Rules USING [Create], RuntimeError USING [BoundsFault], Terminal USING [Current, FrameBuffer, GetBWFrameBuffer, Virtual], TIPUser USING [TIPScreenCoords, TIPTable, InstantiateNewTIPTable], ViewerClasses USING [DestroyProc, NotifyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass, SetNewVersion], ViewerTools USING [GetContents, SetContents] ; IconEditorImplB: CEDAR PROGRAM IMPORTS ChoiceButtons, Commander, CommandTool, Containers, Icons, IconEditorDefs, IconRegistry, Imager, ImagerBackdoor, IO, MBQueue, MessageWindow, Real, Rope, Rules, RuntimeError, PrincOpsUtils, TIPUser, ViewerOps, ViewerTools, FS, Terminal, LFBoundingBox EXPORTS IconEditorDefs = { foreground: ImagerColorDefs.ConstantColor _ Imager.black; background: ImagerColorDefs.ConstantColor _ Imager.white; iconEditorIcon: Icons.IconFlavor = Icons.NewIconFromFile["IconEditor.icons", 0]; iconEditorTipTable: TIPUser.TIPTable = TIPUser.InstantiateNewTIPTable["IconEditor.TIP"]; installationDirectory: Rope.ROPE = CommandTool.CurrentWorkingDirectory[]; StartIconEditor: Commander.CommandProc = { ENABLE UNWIND => NULL; tool: IconEditorDefs.IconHandle _ NEW [IconEditorDefs.IconHandleRec]; { iconFileInfo, iconNumberInfo: ChoiceButtons.PromptDataRef; iconFetchButton: Buttons.Button; iconViewerClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: IconPainter, notify: NotifyEvents, destroy: AboutToDestroy, tipTable: iconEditorTipTable ]]; tool.queue _ MBQueue.Create[]; --create an automaticallly managed queue tool.iconFileName _ installationDirectory.Cat["Sample.icons"]; tool.container _ Containers.Create[info: [name: "Icon Editor", scrollable: FALSE, iconic: TRUE, column: left, icon: iconEditorIcon]]; tool.container.menu _ IconEditorDefs.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 _ MBQueue.CreateButton[q: tool.queue, 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+IconEditorDefs.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 = { handle: IconEditorDefs.IconHandle _ NARROW[clientData]; fetchFile: IO.STREAM; numIconsInFile: IconEditorDefs.Nat; badNews: BOOLEAN _ FALSE; iconInfo: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.IconInfoRec _ [handle, icon, handle.currentIC]]; iconNumberRope: Rope.ROPE _ ViewerTools.GetContents[handle.iconNumberWindow]; iconNumber: IconEditorDefs.Nat; iconFetchFileName: Rope.ROPE _ ViewerTools.GetContents[handle.iconFetchFileWindow]; h: IO.STREAM _ IO.RIS[iconNumberRope]; {ENABLE IO.Error => GOTO BadFile; badNews _ FALSE; iconNumber _ h.GetInt[ ! IO.Error, IO.EndOfStream => { MessageWindow.Append["Type a valid number in the Number window first!", TRUE]; MessageWindow.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 }; fetchFile _ FS.StreamOpen[fileName: iconFetchFileName ! FS.Error => { MessageWindow.Append[iconFetchFileName, TRUE]; MessageWindow.Append[": ", FALSE]; MessageWindow.Append[error.explanation, FALSE]; MessageWindow.Blink[]; badNews _ TRUE; CONTINUE }]; IF badNews THEN RETURN; numIconsInFile _ fetchFile.GetLength[]/(Basics.bytesPerWord*SIZE[IconEditorDefs.IconFileFormat]); IF iconNumber >= numIconsInFile THEN { MessageWindow.Append[message: "Could not fetch icon due to invalid icon number", clearFirst: TRUE]; RETURN } ELSE TRUSTED { fetchFile.SetIndex[iconNumber*(Basics.bytesPerWord*SIZE[IconEditorDefs.IconFileFormat])]; IF shift THEN { --shift means OR new icon bitmap into current bitmap block: REF IconEditorDefs.BitArray _ NEW[IconEditorDefs.BitArray]; [] _ fetchFile.UnsafeGetBlock[block: [base: LOOPHOLE[block], startIndex: 0, count: SIZE[IconEditorDefs.BitArray]*Basics.bytesPerWord] ! RuntimeError.BoundsFault => GOTO BadFile]; FOR h: IconEditorDefs.IntH IN IconEditorDefs.IntH DO FOR w: IconEditorDefs.IntW IN IconEditorDefs.IntW DO handle.icons[LOOPHOLE[handle.currentIC]].bits[h].b[w] _ handle.icons[LOOPHOLE[handle.currentIC]].bits[h].b[w] OR block[h].b[w]; ENDLOOP; ENDLOOP; } ELSE [] _ fetchFile.UnsafeGetBlock[block: [base: LOOPHOLE[handle.icons[LOOPHOLE[handle.currentIC]]], startIndex: 0, count: SIZE[IconEditorDefs.IconFileFormat]*Basics.bytesPerWord] ! RuntimeError.BoundsFault => GOTO BadFile]; fetchFile.Close[]; 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]; } }; FillIcon: PUBLIC PROC [handle: IconEditorDefs.IconHandle] = TRUSTED { iconInfo: IconEditorDefs.IconInfoRef; handle.currentIC _ IconEditorDefs.GetNewFlavor[handle]; handle.currentIconRep _ handle.icons[LOOPHOLE[handle.currentIC]] _ NEW[IconEditorDefs.IconFileFormat]; iconInfo _ NEW[IconEditorDefs.IconInfoRec _ [handle, newIcon, handle.currentIC]]; handle.numberOfIcons _ handle.numberOfIcons + 1; ViewerOps.SetNewVersion[handle.container]; handle.icons[LOOPHOLE[handle.currentIC]] _ GetIconBitmap[]; IF LOOPHOLE[handle.currentIC, IconEditorDefs.Nat] >= IconEditorDefs.maxIconsOnDisplay THEN handle.startDisplay _ (handle.startDisplay + 1) MOD handle.numberOfIcons; ViewerOps.PaintViewer[viewer: handle.viewer, hint: client, whatChanged: NIL, clearClient: FALSE]; }; GetIconBitmap: PROC [] RETURNS [ir: IconEditorDefs.IconRef] ~ TRUSTED { x,y,w,h: NAT; bbtSpace: PrincOps.BBTableSpace; bbt: PrincOps.BBptr _ PrincOpsUtils.AlignedBBTable[@bbtSpace]; vt: Terminal.Virtual = Terminal.Current[]; frameBuf: Terminal.FrameBuffer _ Terminal.GetBWFrameBuffer[vt]; [x,y,w,h] _ LFBoundingBox.GetArea[]; y _ MAX[vt.bwHeight-y-h, 0]; --LFBB uses lower left, vt uses top and upper left ir _ NEW[IconEditorDefs.IconFileFormat]; --get new storage for bit array, etc. bbt.src _ [word: frameBuf.base+(LONG[y]*frameBuf.wordsPerLine)+(x/16), bit: x MOD 16]; bbt.srcDesc _ [srcBpl[srcBpl: frameBuf.wordsPerLine*Basics.bitsPerWord]]; bbt.width _ IconEditorDefs.iconW; bbt.height _ IconEditorDefs.iconH; bbt.dst _ [word: @ir.bits, bit: 0]; bbt.dstBpl _ IconEditorDefs.iconW; bbt.flags _ [disjoint: TRUE, gray: FALSE]; PrincOpsUtils.BITBLT[bbt]; --copy screen bitmap into IconFileFormat }; UndoProc: PUBLIC Menus.MenuProc = { handle: IconEditorDefs.IconHandle _ NARROW[clientData]; iconInfo: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: IconEditorDefs.IconHandle _ NARROW[clientData]; iconInfo: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: PROC [handle: IconEditorDefs.IconHandle, context: Imager.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: IconEditorDefs.IconInfoRef; iconContext: Imager.Context _ context; boundRect: Imager.Rectangle _ ImagerBackdoor.GetBounds[iconContext]; bounds: Imager.Box _ [xmin: boundRect.x, ymin: boundRect.y, xmax: boundRect.x+boundRect.w, ymax: boundRect.y+boundRect.h]; MessageWindow.Append[clearFirst: TRUE, message: ""]; IF whatChanged=NIL THEN { handle: IconEditorDefs.IconHandle _ NARROW[self.data]; IconEditorDefs.LayoutBoard[handle, bounds ! IconEditorDefs.ViewerNoGood => GOTO Done]; IF ~clear THEN ClearScreen[iconContext, bounds]; 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 ! IconEditorDefs.ViewerNoGood => GOTO Done]; SELECT iconInfo.update FROM screen => { ClearScreen[iconContext, bounds]; 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[iconContext, bounds]; 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: IconEditorDefs.IconHandle _ NARROW[self.data]; handle.iconFile.Close[]; }; XfromIC: PROC[handle: IconEditorDefs.IconHandle, ic: IconEditorDefs.IconFlavor] RETURNS [IconEditorDefs.Nat] = { i: IconEditorDefs.Nat _ LOOPHOLE[ic]; realFlavor: IconEditorDefs.Nat _ (i - handle.startDisplay + handle.numberOfIcons) MOD handle.numberOfIcons; RETURN [handle.icX+(IconEditorDefs.distX/2) + (realFlavor MOD handle.numIconsPerRow) * (IconEditorDefs.iconW+IconEditorDefs.distX)]; }; YfromIC: PROC[handle: IconEditorDefs.IconHandle, ic: IconEditorDefs.IconFlavor] RETURNS [IconEditorDefs.Nat] = { i: IconEditorDefs.Nat _ LOOPHOLE[ic]; realFlavor: IconEditorDefs.Nat _ (i - handle.startDisplay + handle.numberOfIcons) MOD handle.numberOfIcons; RETURN [handle.icY + (IconEditorDefs.distY/2) + (handle.numIconsPerCol-1-realFlavor / handle.numIconsPerRow) * (IconEditorDefs.iconH+IconEditorDefs.distY)]; }; ICfromXY: PROC[handle: IconEditorDefs.IconHandle, x, y: REAL] RETURNS [ignore: BOOLEAN, ic: IconEditorDefs.IconFlavor] = { xC, yC: IconEditorDefs.Nat; possibleIC, theIC: IconEditorDefs.Nat; iconsOnDisplay: IconEditorDefs.Nat _ MIN[handle.numberOfIcons, IconEditorDefs.maxIconsOnDisplay]; ignore _ FALSE; xC _ Real.FixC[x]; IF xC > handle.icX + (IconEditorDefs.distX/2) THEN xC _ (xC-handle.icX-IconEditorDefs.distX/2)/(IconEditorDefs.iconW+IconEditorDefs.distX) ELSE { ignore _ TRUE; xC _ 0}; yC _ Real.FixC[y]; IF yC > handle.icY + (IconEditorDefs.distY/2) THEN yC _ (yC-handle.icY-IconEditorDefs.distY/2)/(IconEditorDefs.iconH+IconEditorDefs.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: IconEditorDefs.IconHandle, x, y: REAL] RETURNS [i, j: IconEditorDefs.Nat] = { i _ IF x > handle.boardSize THEN IconEditorDefs.intWBound ELSE Real.FixI[x/handle.unit]; j _ MAX[IconEditorDefs.intHBound-Real.FixI[y/handle.unit], 0]; }; DeleteIcon: PROC [handle: IconEditorDefs.IconHandle] = { IF LOOPHOLE[handle.currentIC, IconEditorDefs.Nat] < handle.numberOfIcons - 1 THEN { FOR i: IconEditorDefs.Nat IN [LOOPHOLE[handle.currentIC, IconEditorDefs.Nat] .. handle.numberOfIcons-1) DO handle.icons[LOOPHOLE[i]] _ handle.icons[LOOPHOLE[i+1]]; ENDLOOP; handle.icons[handle.numberOfIcons - 1] _ NIL; --forget prior last icon } 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: IconEditorDefs.IconHandle, flavor: IconEditorDefs.IconFlavor] = { handle.icons[LOOPHOLE[flavor]].bits _ handle.savedBitMap; }; DrawIcons: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context] = { FOR i: IconEditorDefs.Nat IN [0..MIN[handle.numberOfIcons, IconEditorDefs.maxIconsOnDisplay]) DO DrawIcon[handle, context, (handle.startDisplay + i) MOD handle.numberOfIcons]; ENDLOOP; }; DrawBit: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context, x, y: IconEditorDefs.Nat] = { DrawBitProc: PROC = { Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskBox[context, [xmin: lx+1.0, ymin: by+1.0, xmax: lx+handle.unit, ymax: by+handle.unit]]; }; lx: REAL _ x*handle.unit; by: REAL _ (IconEditorDefs.intHBound-y)*handle.unit; Imager.DoSaveAll[context: context, action: DrawBitProc]; }; ClearScreen: PROC [context: Imager.Context, bounds: Imager.Box] = { Imager.SetColor[context, background]; Imager.MaskBox[context: context, box: bounds]; Imager.SetColor[context, foreground]; }; DrawBox: PROC [context: Imager.Context, x0, y0, x1, y1: IconEditorDefs.Nat] = { DrawBoxProc: PROC = { DrawBoxPathProc: ImagerPath.PathProc = { moveTo[[x0, y0]]; lineTo[[x0, y1]]; lineTo[[x1, y1]]; lineTo[[x1, y0]]; lineTo[[x0, y0]]; }; Imager.SetColor[context, ImagerBackdoor.invert]; Imager.SetStrokeWidth[context: context, strokeWidth: IconEditorDefs.normalThickness]; Imager.MaskStroke[context: context, path: DrawBoxPathProc]; }; Imager.DoSaveAll[context: context, action: DrawBoxProc]; }; DrawIcon: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context, index: IconEditorDefs.Nat] = { IF handle.icons[LOOPHOLE[index]] = NIL THEN RETURN -- Just to be safe ELSE { base: LONG POINTER _ LOOPHOLE[handle.icons[LOOPHOLE[index]]]; wordsPerLine: NAT _ IconEditorDefs.iconW/Basics.bitsPerWord; ImagerBackdoor.DrawBits[context: context, base: base, wordsPerLine: wordsPerLine, sMin: 0, fMin: 0, sSize: IconEditorDefs.iconW, fSize: IconEditorDefs.iconH, tx: XfromIC[handle: handle, ic: LOOPHOLE[index]], ty: YfromIC[handle: handle, ic: LOOPHOLE[index]] + IconEditorDefs.iconH]; }; }; DrawBoard: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context] = { DrawBoardProc: PROC = { bs: INTEGER _ Real.FixI[handle.boardSize]; Imager.SetColor[context, background]; Imager.MaskRectangleI[context: context, x: 0, y: 0, w: bs, h: bs]; Imager.SetColor[context, foreground]; FOR i: IconEditorDefs.Nat IN [0..IconEditorDefs.intHBound+1] DO Imager.MaskRectangleI[context: context, x: i*handle.unit, y: 0, w: 1, h: bs]; Imager.MaskRectangleI[context: context, x: 0, y: i*handle.unit, w: bs, h: 1]; ENDLOOP; }; Imager.DoSaveAll[context: context, action: DrawBoardProc]; DrawCurrentIcon[handle, context]; handle.drewRectangle _ handle.drewLine _ FALSE; handle.functionNotApplied _ FALSE; }; DrawCurrentIcon: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context] = { DrawCIProc: PROC = { Imager.SetColor[context, ImagerBackdoor.invert]; FOR i: IconEditorDefs.Nat IN IconEditorDefs.IntH DO FOR j: IconEditorDefs.Nat IN IconEditorDefs.IntW DO IF handle.currentIconRep.bits[i].b[j] THEN { lx: REAL _ j*handle.unit; by: REAL _ (IconEditorDefs.intHBound-i)*handle.unit; Imager.MaskBox[context, [xmin: lx+1.0, ymin: by+1.0, xmax: lx+handle.unit, ymax: by+handle.unit]]; }; ENDLOOP; ENDLOOP; }; Imager.DoSave[context: context, action: DrawCIProc]; }; DrawRectangle: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context, rect: IconEditorDefs.RectangleRec] = { rX0, rY0, rX1, rY1: IconEditorDefs.Nat; rX0 _ rect.x*handle.unit - 1; -- top right corner rY0 _ (IconEditorDefs.intHBound-rect.y + 1)*handle.unit + 1; rX1 _ (rect.x + rect.w)*handle.unit + 1; -- bottom left corner rY1 _ (IconEditorDefs.intHBound-rect.y - rect.h + 1)*handle.unit - 1; DrawBox[context, rX0, rY0, rX1, rY1]; handle.drewRectangle _ TRUE; }; DrawBorder: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context] = { x0, y0, x1, y1: IconEditorDefs.Nat; 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]; }; SketchLine: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context] = { SLProc: PROC = { SLPathProc: ImagerPath.PathProc = { moveTo[[line.x1, line.y1]]; lineTo[[line.x2, line.y2]]; }; Imager.SetColor[context, ImagerBackdoor.invert]; Imager.SetStrokeWidth[context: context, strokeWidth: IconEditorDefs.normalThickness]; Imager.MaskStroke[context: context, path: SLPathProc]; }; line: IconEditorDefs.LineRec _ IconEditorDefs.ComputeEndPoints[handle, handle.currentLine]; Imager.DoSaveAll[context: context, action: SLProc]; handle.drewLine _ TRUE; }; SetCurrentIcon: PROC [handle: IconEditorDefs.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: IconEditorDefs.IconHandle, x, y: REAL] RETURNS [BOOLEAN] = { xC, yC: IconEditorDefs.Nat; [xC, yC] _ BoardCoords[handle, x, y]; RETURN [handle.currentIconRep.bits[yC].b[xC]]; }; AddBit: PROC [handle: IconEditorDefs.IconHandle, context: Imager.Context, x, y: REAL] = { xC, yC: IconEditorDefs.Nat; [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: IconEditorDefs.IconHandle, context: Imager.Context, x, y: REAL] = { xC, yC: IconEditorDefs.Nat; [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: IconEditorDefs.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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.IconInfoRec _ [handle, icon, handle.currentIC]]; IF PrincOpsUtils.IsBound[LOOPHOLE[IconRegistry.IsRegistered]] THEN ViewerTools.SetContents[handle.iconNameWindow, IconRegistry.IsRegistered[ fileName: ViewerTools.GetContents[handle.iconFileWindow], index: LOOPHOLE[handle.currentIC, IconEditorDefs.Nat]].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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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: IconEditorDefs.IconInfoRef _ NEW[IconEditorDefs.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; }; Commander.Register["IconEditor", StartIconEditor, "create a tool to create and edit icon files"]; }. „IconEditorImplB.mesa Last Edited by: Ken Pier, May 31, 1985 10:28:06 am PDT Set the file index to point at the icon we wish to fetch. Since each icon takes up Basics.bytesPerWord*SIZE[IconFileFormat] bytes, we index into the file by multiples of this. Now read in the block allows any screen bit map to be converted to icon format make the new icon contain the screen bit map before we paint the screen, make sure new icon is visible make sure we have at least one icon left after we delete PaintProc: TYPE = PROC [self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOL _ FALSE]; we better find out what viewer we want to be dealing with Erase the previous rectangle or line if necessary Erase the old rectangle Erase the previous line or rectangle if necessary Clear up the rectangle marking just in case Erase the old line Just to be safe, close the most recent icon file we were working with We must find some way of getting the handle from the viewer deletes the current icon and then compacts the array of icons. the icon we wish to delete is in the middle of the array of icons; Compact. we are deleting the last icon in the array. now let currentIC be the previous flavor. Since we always must have at least one icon in existance, we will always have a previous flavor Draws a box on the screen with bottom left corner (x0, y0) and top right corner (x1, y1) THIS PROC WILL PROBABLY NOT DO THE RIGHT THING!! CHECK IT !! Draws a rectangle on the drawing board draws a thin border around newly created icons Draws a thin line from one endpoint to another NotifyProc: TYPE = PROC [self: Viewer, input: LIST OF REF ANY]; Κž˜Icodešœ™Kšœ6™6K˜šΟk ˜ Kšœœ˜)Kšœœ ˜Kšœœ"˜5Kšœ œ˜(Kšœ œ˜,Kšœ œ/˜?Kšœœ˜K˜Kšœ œ˜"Kšœœ˜*Kšœœ{˜‡Kšœœ˜3Kšœœ˜&Kšœ œ ˜Kšœœ0œ œ˜_Kšœœ ˜Kšœœ˜,Kšœœ˜(Kšœœ˜-Kšœ œ˜%Kšœœœ ˜6Kšœœ˜Kšœœœ˜Kšœœ ˜Kšœ œ˜!Kšœ œ3˜AKšœœ5˜Bšœœ:˜MK˜—Kšœ œA˜PKšœ œ˜,K˜—K˜šΟbœœ˜Kšœqœkœ˜Kšœ˜K˜K˜:K˜:K˜PK˜XKšœœ)˜IK˜šžœ˜*Kšœœœ˜Kšœ"œ ˜E˜K˜:K˜ šœ-œ!˜QK˜K˜K˜K˜K˜—K˜KšœΟc(˜GK˜>˜>Kšœ œ œ'˜F—K˜6K˜˜aK˜(—K˜.K˜@K˜xKšœ0Ÿ˜7K˜šœp˜pKšœœ0œ˜J—K˜”K˜2K˜€K˜3K˜EK˜rK˜<˜XKšœ œ œ3˜S—K˜4K˜4˜WKšœ#œ ˜1—K˜'Kšœ ˜KšœUœ˜[K˜—K˜K˜—šž œ˜"Kšœ$œ ˜7Kšœ œœ˜Kšœ#˜#Kšœ œœ˜Kšœ'œ@˜jKšœœ4˜MKšœ˜Kšœœ7˜SKš œœœœœ˜&šœœœ œ ˜!Kšœ œ˜šœœœ˜6KšœHœ˜NKšœ!œœ˜0K˜—Kšœ œœ˜šœœœ˜5˜PKšœ œ˜—Kš˜K˜—šœ œ7˜EKšœ(œ˜.Kšœœ˜"Kšœ(œ˜/Kšœ!œ˜/K˜—Kšœ œœ˜Kšœ<œ!˜ašœœ˜&˜PKšœ œ˜—Kš˜K˜—šœœ˜KšœS™SKšœ\™\Kšœ3œ"˜YKšœ™šœœŸ4˜DKšœœœ˜BKšœ,œœMœ ˜²šœœ˜4šœœ˜4Kšœ œ0œ!œ˜Kšœ˜—Kšœ˜—Kšœ˜—Kš œ-œœ,œSœ ˜ΰK˜Kšœ%œ˜AK˜—K˜*Kšœ\œ˜cK˜Kšœ˜šœ ˜ Kšœjœ˜p—K˜—K˜K˜—šΟnœœœ'œ˜EKšœ8™8K˜%K˜7Kšœ%œœ ˜fKšœ œC˜QK˜0K˜*Kšœ,™,Kšœ œ&˜;Kšœ9™9KšœœKœ˜[Kšœ0œ˜IšœHœ˜LKšœ œ˜—K˜K˜—š  œœœ œ˜GKšœ œ˜ K˜ K˜>K˜*K˜?K˜$KšœœŸ2˜OKšœœ"Ÿ%˜OKšœ œ*œ˜VK˜IK˜!K˜"K˜#K˜"Kšœœœ˜*KšœœŸ(˜CK˜K˜—šžœœ˜#Kšœ$œ ˜7Kšœ'œ@˜jK˜*K˜˜NKšœ œ˜—K˜K˜—šžœœ˜)Kšœ$œ ˜7Kšœ'œB˜lKšœ8™8šœœ˜"KšœPœ˜VK˜Kšœ˜K˜—Kšœ?œœ˜MK˜K˜*Kšœ\œ˜cK˜K˜—š œœA˜NKšœœ˜"šœœ:˜VKšœ˜K˜—Kšœœ1œ˜OK˜K˜—šž œœ˜/Kšœ œœ6œ œœœœ™{Kšœœœ˜K˜%K˜&K˜DK˜zKšœ!œ˜4šœ œœ˜Kšœ9™9Kšœ$œ ˜6KšœKœ˜VKšœœ"˜0K˜˜AK˜&—K˜K˜—šœ˜Kšœ œ˜KšœTœ˜_šœ˜˜ K˜!K˜1K˜(˜$K˜7K˜8—K˜(K˜—K˜1˜ Kšœ'œ4˜cK˜'K˜—˜Kšœœ@˜YKšœ>˜BK˜—˜ K˜!K˜(K˜(K˜)K˜—˜ šœœ˜#Kšœ1™1K˜&Kšœ%œ˜*˜AK˜)—K˜=K˜=K˜'K˜'K˜—šœ˜Kšœ™K˜N˜4K˜5—˜EK˜.—K˜NK˜—K˜—˜ šœœ˜#Kšœ1™1K˜&Kšœ+™+K˜'K˜'K˜'K˜'Kšœ%œ˜*˜4K˜5—K˜2Kšœ2Ÿ$˜V˜K˜O—K˜—šœ˜Kšœ™K˜)˜4K˜5—˜K˜O—K˜)K˜—K˜—˜ K˜GK˜—Kšœ˜—K˜—KšœœŸ˜&Kšœ œ˜K˜K˜—šžœœ˜4Kšœœœ˜Kšœ$œ ˜6KšœE™EKšœ;™;K˜K˜K˜—š œœCœ˜pKšœœ˜%šœR˜UK˜—šœ4œ˜VK˜-—K˜K˜—š œœCœ˜pKšœœ˜%šœR˜UK˜—šœO˜UK˜F—K˜K˜—Kš œœ*œ˜=šœ œ$˜K˜K˜—š  œœ(˜8Kšœ>™>šœœBœ˜SKšœK™KšœœœB˜jKšœ œœ˜8Kšœ˜—Kšœ)œŸ˜FK˜—šœ˜Kšœ-™-Kšœ œœ˜/KšœQ™QKšœ8™8Kšœœ˜*K˜—K˜0Kšœœ˜,Kšœ%œ˜AK˜K˜—š œœK˜UKšœ œ$˜9K˜K˜—š  œœA˜Pšœœœ:˜`Kšœ4œ˜NKšœ˜—K˜K˜—š œœ[˜hš  œœ˜K˜0Kšœb˜bK˜—Kšœœ˜Kšœœ,˜4K˜8K˜K˜—š  œœ2˜CK˜%K˜.K˜%K˜K˜—š œœB˜OKšœX™Xš  œœ˜˜(K˜K˜K˜K˜K˜K˜—K˜0K˜UK˜;K˜—K˜8K˜K˜—š œœ\˜jKšœ<™K˜EK˜%Kšœœ˜K˜K˜—š  œœA˜QKšœ.™.Kšœ#˜#K˜'K˜)K˜#K˜#K˜!K˜K˜—š  œœA˜QKšœ.™.š œœ˜˜#K˜K˜K˜—K˜0K˜UK˜6K˜—K˜[K˜3Kšœœ˜K˜K˜—š  œœ+œœ œ˜cK˜K˜'šœ œ˜K˜Kšœ%œ˜AK˜—K˜K˜—š  œœ+œœœ˜RKšœ˜K˜%Kšœ(˜.K˜K˜—š œœDœ˜YKšœ˜K˜%Kšœ'œ˜,K˜!Kšœœ˜6K˜K˜—š  œœDœ˜\Kšœ˜K˜%Kšœ'œ˜-K˜!Kšœœ˜6K˜K˜—š  œŸ˜AKšœ?™?KšœœœŸ˜&Kšœœ˜Kšœœ˜Kšœ$œ ˜6š  œœœ˜$šœœ˜Kšœœ˜˜ šœœœ˜@Kšœ œ*˜:šœ œœ˜Kšœ'œ@˜jKšœœ˜B˜.˜K˜9Kšœœ0Ÿ˜F——˜:Kšœ$œ˜+—K˜—K˜—K˜—šœ Ÿ˜ šœœœ˜AK˜*šœ(œ˜0Kšœ'œT˜~˜GKšœœ˜—K˜—K˜—K˜—˜ šœœœ˜Ašœ'œ˜GK˜9—Kšœœ˜K˜*˜QKšœ œ˜—K˜—K˜—˜ šœœœ˜Ašœ'œ˜GK˜9—Kšœœ˜K˜*˜QKšœ œ˜—K˜—K˜—˜šœœœ˜Ašœ'œ˜GK˜9—Kšœœ˜K˜*˜PKšœ œ˜—K˜—K˜—˜šœœœ˜Ašœ'œE˜oK˜—Kšœœ˜K˜*˜QKšœ œ˜—K˜—K˜—Kšœ˜—KšœŸ˜—K˜šœ œœœœœœ˜Dšœœ˜˜Kšœ.œ˜4K˜—Kšœœ˜Kšœ˜—Kšœ˜—K˜K˜—K˜aK˜——…—fp€’