WMImageGrid.Mod 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. (*Author: Stephan Koster; Purpose: Components to display multiple images arranged in a grid*)
  2. MODULE WMImageGrid;
  3. IMPORT WMWindowManager, Graphics:=WMGraphics, Raster, Messages:=WMMessages, Rectangles:=WMRectangles;
  4. TYPE Message=Messages.Message;
  5. TYPE Rectangle=Rectangles.Rectangle;
  6. TYPE Grid=ARRAY OF ARRAY OF Graphics.Image;
  7. TYPE GridWindow* = OBJECT(WMWindowManager.Window)
  8. VAR
  9. imgs*: POINTER TO Grid;
  10. background*: Graphics.Image;
  11. canvas* : Graphics.BufferCanvas;
  12. canvasGen-: Graphics.CanvasGenerator;
  13. pointerThreshold*,
  14. maxInterpolation* : LONGINT; (* allows limiting the interpolation degree on Draw *)
  15. hs,ws: POINTER TO ARRAY OF LONGINT;
  16. totalW, totalH: LONGINT;
  17. gap: LONGINT;
  18. PROCEDURE &Init1*( CONST Ws, Hs: ARRAY OF LONGINT; alpha : BOOLEAN);
  19. VAR
  20. i,j: LONGINT;
  21. rm: Raster.Mode;
  22. pix: Raster.Pixel;
  23. BEGIN
  24. gap:=10;
  25. NEW(SELF.ws, LEN(Ws));
  26. NEW(SELF.hs, LEN(Hs));
  27. FOR i:=0 TO LEN(Ws,0)-1 DO
  28. ASSERT(Ws[i]>0);
  29. SELF.ws[i]:=Ws[i];
  30. totalW:=totalW+Ws[i];
  31. END;
  32. totalW:=totalW+gap*(LEN(Ws,0)-1);
  33. FOR i:=0 TO LEN(Hs,0)-1 DO
  34. ASSERT(Hs[i]>0);
  35. SELF.hs[i]:=Hs[i];
  36. totalH:=totalH+Hs[i];
  37. END;
  38. totalH:=totalH+gap*(LEN(Hs,0)-1);
  39. Init(totalW, totalH, alpha); (*parent constructor*)
  40. NEW(imgs,LEN(Ws,0),LEN(Hs,0));
  41. FOR i:=0 TO LEN(Ws,0)-1 DO
  42. FOR j:=0 TO LEN(Hs,0)-1 DO
  43. NEW(imgs[i,j]);
  44. 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;
  45. END
  46. END;
  47. NEW(background);
  48. IF alpha THEN Raster.Create(background, totalW, totalH, Raster.BGRA8888) ELSE Raster.Create(background, totalW, totalH, WMWindowManager.format) END;
  49. Raster.InitMode(rm, Raster.srcOverDst);
  50. Raster.SetRGBA(pix, 0,0,0,255);
  51. Raster.Fill(background, 0,0, totalW,totalH,pix, rm);
  52. SetCanvasGenerator(Graphics.GenCanvas);
  53. pointerThreshold := 1; (* invisible pixels are treated as invisible *)
  54. maxInterpolation := Graphics.ScaleBilinear;
  55. END Init1;
  56. PROCEDURE SetCanvasGenerator*(canvasGen:Graphics.CanvasGenerator);
  57. BEGIN{EXCLUSIVE}
  58. SELF.canvasGen:=canvasGen; IF background # NIL THEN canvas:=canvasGen(background); END;
  59. IF manager # NIL THEN manager.AddVisibleDirty(SELF, bounds) END
  60. END SetCanvasGenerator;
  61. PROCEDURE IsHit(x, y : LONGINT) : BOOLEAN;
  62. VAR w, h : LONGINT; fx, fy : REAL;
  63. BEGIN
  64. w := GetWidth(); h := GetHeight();
  65. IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) THEN
  66. fx := totalW/ w;
  67. fy := totalH/ h;
  68. RETURN Graphics.IsBitmapHit(ENTIER(x * fx), ENTIER(y * fy), pointerThreshold, background)
  69. ELSE RETURN Graphics.IsBitmapHit(x, y, pointerThreshold, background)
  70. END
  71. END IsHit;
  72. PROCEDURE Draw*(canvas : Graphics.Canvas; w, h, q : LONGINT);
  73. VAR
  74. mode: LONGINT;
  75. isScaled: BOOLEAN;
  76. i,j: LONGINT;
  77. x,y: LONGINT;
  78. PROCEDURE DrawSingle(CONST img: Graphics.Image; offX,offY: LONGINT; isScaled: BOOLEAN; mode: LONGINT);
  79. VAR
  80. wscaled,hscaled: LONGINT;
  81. BEGIN
  82. IF img # NIL THEN
  83. IF ~isScaled THEN
  84. canvas.DrawImage(offX,offY,img, mode);
  85. ELSE
  86. offX:=offX*w DIV totalW; (*these are not pixel perfect, but I can't think of anything better*)
  87. offY:=offY*h DIV totalH;
  88. wscaled:=img.width*w DIV totalW; (*this means if the image is not actually the size suggested by ws[i],hs[j], then it won't be blown up to fill the space.*)
  89. hscaled:=img.height*h DIV totalH;
  90. canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height), Rectangles.MakeRect(offX,offY, offX+wscaled, offY+hscaled), mode, MIN(q,maxInterpolation));
  91. END
  92. END;
  93. END DrawSingle;
  94. BEGIN
  95. IF useAlpha THEN
  96. mode:=Graphics.ModeSrcOverDst;
  97. ELSE
  98. mode:=Graphics.ModeCopy;
  99. END;
  100. isScaled:=~((w = totalW) & (h = totalH));
  101. IF reduceQuality THEN q := 0 END;
  102. DrawSingle(background, 0,0, isScaled, mode);
  103. x:=0;
  104. FOR i:=0 TO LEN(imgs,0)-1 DO
  105. y:=0;
  106. FOR j:=0 TO LEN(imgs,1)-1 DO
  107. DrawSingle(imgs[i,j], x,y, isScaled,mode);
  108. y:=y+hs[j]+gap;
  109. END;
  110. x:=x+ws[i]+gap;
  111. END;
  112. INC(timestamp);
  113. END Draw;
  114. PROCEDURE Invalidate*(rect : Rectangle);
  115. VAR w, h : LONGINT; fx, fy : LONGREAL;
  116. BEGIN
  117. w := GetWidth(); h := GetHeight();
  118. IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) THEN
  119. fx := w / totalW; fy := h / totalH;
  120. rect.l := ENTIER(rect.l * fx); rect.t := ENTIER(rect.t * fy);
  121. rect.r := ENTIER(rect.r * fx + 0.5); rect.b := ENTIER(rect.b * fy + 0.5)
  122. END;
  123. Invalidate^(rect)
  124. END Invalidate;
  125. PROCEDURE Handle*(VAR m : Message);
  126. VAR w, h : LONGINT; fx, fy : REAL;
  127. BEGIN
  128. w := GetWidth(); h := GetHeight();
  129. IF (w > 0) & (h > 0) & ((w # totalW) OR (h # totalH)) & (m.msgType = Messages.MsgPointer) THEN
  130. m.x := m.x-bounds.l; m.y := m.y-bounds.t;
  131. fx := totalW/ w;
  132. fy := totalH/ h;
  133. m.x := ENTIER(m.x * fx); m.y := ENTIER(m.y * fy);
  134. m.x := m.x + bounds.l; m.y := m.y+bounds.l;
  135. ELSIF m.msgType = Messages.MsgInvalidate THEN
  136. IF m.msgSubType = Messages.MsgSubAll THEN
  137. Invalidate(Rectangles.MakeRect(0, 0, totalW, totalH));
  138. ELSE
  139. HALT(200)
  140. END;
  141. ELSE
  142. Handle^(m)
  143. END;
  144. END Handle;
  145. END GridWindow;
  146. PROCEDURE Test*();
  147. VAR
  148. w: GridWindow;
  149. Ws,Hs: ARRAY 3 OF LONGINT;
  150. i: LONGINT;
  151. rm: Raster.Mode;
  152. pix: Raster.Pixel;
  153. BEGIN
  154. FOR i:=0 TO 2 DO
  155. Ws[i]:=100*i+30;
  156. Hs[i]:=20+200*i;
  157. END;
  158. NEW(w,Ws,Hs, TRUE);
  159. Raster.InitMode(rm, Raster.srcOverDst);
  160. Raster.SetRGBA(pix, 255,0,0,255);
  161. Raster.Fill(w.imgs[0,0], 0,0, Ws[0],Hs[0],pix, rm);
  162. Raster.SetRGBA(pix, 0,255,0,255);
  163. Raster.Fill(w.imgs[1,1], 0,0, Ws[1],Hs[1],pix, rm);
  164. Raster.SetRGBA(pix, 0,0,255,255);
  165. Raster.Fill(w.imgs[2,2], 0,0, Ws[2],Hs[2],pix, rm);
  166. WMWindowManager.DefaultAddWindow(w);
  167. END Test;
  168. END WMImageGrid.
  169. SystemTools.FreeDownTo WMImageGrid~
  170. WMImageGrid.Test~