(*Author: Stephan Koster; Purpose: Components to display multiple images arranged in a grid*) MODULE WMImageGrid; IMPORT WMWindowManager, Graphics:=WMGraphics, Raster, Messages:=WMMessages, Rectangles:=WMRectangles; TYPE Message=Messages.Message; TYPE Rectangle=Rectangles.Rectangle; TYPE Grid=ARRAY OF ARRAY OF Graphics.Image; TYPE GridWindow* = OBJECT(WMWindowManager.Window) VAR imgs*: POINTER TO Grid; background*: Graphics.Image; canvas* : Graphics.BufferCanvas; canvasGen-: Graphics.CanvasGenerator; pointerThreshold*, maxInterpolation* : LONGINT; (* allows limiting the interpolation degree on Draw *) totalW, totalH: LONGINT; gap: LONGINT; PROCEDURE &Init1*( CONST Ws, Hs: ARRAY OF LONGINT; alpha : BOOLEAN); VAR i,j: LONGINT; rm: Raster.Mode; pix: Raster.Pixel; BEGIN gap:=10; FOR i:=0 TO LEN(Ws,0)-1 DO ASSERT(Ws[i]>0); totalW:=totalW+Ws[i]; END; totalW:=totalW+gap*(LEN(Ws,0)-1); FOR i:=0 TO LEN(Hs,0)-1 DO ASSERT(Hs[i]>0); totalH:=totalH+Hs[i]; END; totalH:=totalH+gap*(LEN(Hs,0)-1); Init(totalW, totalH, alpha); (*parent constructor*) NEW(imgs,LEN(Ws,0),LEN(Hs,0)); FOR i:=0 TO LEN(Ws,0)-1 DO FOR j:=0 TO LEN(Hs,0)-1 DO NEW(imgs[i,j]); IF alpha THEN Raster.Create(imgs[i,j], Ws[i], Hs[j], Raster.BGRA8888) ELSE Raster.Create(imgs[i,j], Ws[i], Hs[j], WMWindowManager.format) END; END END; NEW(background); IF alpha THEN Raster.Create(background, totalW, totalH, Raster.BGRA8888) ELSE Raster.Create(background, totalW, totalH, WMWindowManager.format) END; Raster.InitMode(rm, Raster.srcOverDst); Raster.SetRGBA(pix, 0,0,0,255); Raster.Fill(background, 0,0, totalW,totalH,pix, rm); SetCanvasGenerator(Graphics.GenCanvas); pointerThreshold := 1; (* invisible pixels are treated as invisible *) maxInterpolation := Graphics.ScaleBilinear; END Init1; PROCEDURE SetCanvasGenerator*(canvasGen:Graphics.CanvasGenerator); BEGIN{EXCLUSIVE} SELF.canvasGen:=canvasGen; IF background # NIL THEN canvas:=canvasGen(background); END; IF manager # NIL THEN manager.AddVisibleDirty(SELF, bounds) END END SetCanvasGenerator; PROCEDURE IsHit(x, y : LONGINT) : BOOLEAN; VAR w, h : LONGINT; fx, fy : REAL; BEGIN w := GetWidth(); h := GetHeight(); IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) THEN fx := totalW/ w; fy := totalH/ h; RETURN Graphics.IsBitmapHit(ENTIER(x * fx), ENTIER(y * fy), pointerThreshold, background) ELSE RETURN Graphics.IsBitmapHit(x, y, pointerThreshold, background) END END IsHit; PROCEDURE Draw*(canvas : Graphics.Canvas; w, h, q : LONGINT); VAR mode: LONGINT; isScaled: BOOLEAN; i,j: LONGINT; x,y: LONGINT; PROCEDURE DrawSingle(CONST img: Graphics.Image; offX,offY: LONGINT; isScaled: BOOLEAN; mode: LONGINT); VAR wscaled,hscaled: LONGINT; BEGIN IF img # NIL THEN IF ~isScaled THEN canvas.DrawImage(offX,offY,img, mode); ELSE offX:=offX*w DIV totalW; (*these are not pixel perfect, but I can't think of anything better*) offY:=offY*h DIV totalH; wscaled:=img.width*w DIV totalW; hscaled:=img.height*h DIV totalH; canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height), Rectangles.MakeRect(offX,offY, offX+wscaled, offY+hscaled), mode, MIN(q,maxInterpolation)); END END; END DrawSingle; BEGIN IF useAlpha THEN mode:=Graphics.ModeSrcOverDst; ELSE mode:=Graphics.ModeCopy; END; isScaled:=~((w = totalW) & (h = totalH)); IF reduceQuality THEN q := 0 END; DrawSingle(background, 0,0, isScaled, mode); x:=0; FOR i:=0 TO LEN(imgs,0)-1 DO y:=0; FOR j:=0 TO LEN(imgs,1)-1 DO DrawSingle(imgs[i,j], x,y, isScaled,mode); y:=y+imgs[0,j].height+gap; END; x:=x+imgs[i,0].width+gap; END; INC(timestamp); END Draw; PROCEDURE Invalidate*(rect : Rectangle); VAR w, h : LONGINT; fx, fy : REAL; BEGIN w := GetWidth(); h := GetHeight(); IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) THEN fx := w / totalW; fy := h / totalH; rect.l := ENTIER(rect.l * fx); rect.t := ENTIER(rect.t * fy); rect.r := ENTIER(rect.r * fx + 0.5); rect.b := ENTIER(rect.b * fy + 0.5) END; Invalidate^(rect) END Invalidate; PROCEDURE Handle*(VAR m : Message); VAR w, h : LONGINT; fx, fy : REAL; BEGIN w := GetWidth(); h := GetHeight(); IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) & (m.msgType = Messages.MsgPointer) THEN m.x := m.x-bounds.l; m.y := m.y-bounds.t; fx := totalW/ w; fy := totalH/ h; m.x := ENTIER(m.x * fx); m.y := ENTIER(m.y * fy); m.x := m.x + bounds.l; m.y := m.y+bounds.l; END; Handle^(m) END Handle; END GridWindow; PROCEDURE Test*(); VAR w: GridWindow; Ws,Hs: ARRAY 3 OF LONGINT; i: LONGINT; rm: Raster.Mode; pix: Raster.Pixel; BEGIN FOR i:=0 TO 2 DO Ws[i]:=100*i+30; Hs[i]:=20+200*i; END; NEW(w,Ws,Hs, TRUE); Raster.InitMode(rm, Raster.srcOverDst); Raster.SetRGBA(pix, 255,0,0,255); Raster.Fill(w.imgs[0,0], 0,0, Ws[0],Hs[0],pix, rm); Raster.SetRGBA(pix, 0,255,0,255); Raster.Fill(w.imgs[1,1], 0,0, Ws[1],Hs[1],pix, rm); Raster.SetRGBA(pix, 0,0,255,255); Raster.Fill(w.imgs[2,2], 0,0, Ws[2],Hs[2],pix, rm); WMWindowManager.DefaultAddWindow(w); END Test; END WMImageGrid. SystemTools.FreeDownTo ImageGrid~ ImageGrid.Test~