WMNavigator.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. MODULE WMNavigator; (** AUTHOR "staubesv"; PURPOSE "Viewport in a window for navigation"; *)
  2. (* STATUS: First draft - NOT STABLE!!! *)
  3. IMPORT
  4. Modules, Kernel, Locks, Displays, Raster, Strings, XML, WMRectangles, WMGraphics, WMGraphicUtilities, WMWindowManager, WMComponents;
  5. TYPE
  6. Level = RECORD
  7. x, y, width, height : LONGINT;
  8. END;
  9. OnDrawnProc = PROCEDURE {DELEGATE};
  10. ViewPort* = OBJECT (WMWindowManager.ViewPort);
  11. VAR
  12. backbuffer- : WMGraphics.Image;
  13. deviceRect : WMRectangles.Rectangle;
  14. width, height : LONGINT;
  15. canvas : WMGraphics.BufferCanvas;
  16. state : WMGraphics.CanvasState;
  17. internnavig, navig : BOOLEAN;
  18. fx, fy, inffx, inffy, factor, intfactor : REAL;
  19. lock : Locks.Lock;
  20. onDrawn : OnDrawnProc;
  21. zoomLevel : ARRAY 7 OF Level;
  22. currentZoomLevel : LONGINT;
  23. PROCEDURE &New*;
  24. BEGIN
  25. NEW(backbuffer);
  26. Raster.Create(backbuffer, 1280, 1024, Raster.DisplayFormat(Displays.color8888));
  27. range.l := 0; range.t := 0;
  28. range.r := range.l + 1280; range.b := range.t + 1024;
  29. width := 1280; height := 1024;
  30. deviceRect.l := 0; deviceRect.t := 0;
  31. deviceRect.r := 1280; deviceRect.b := 1024;
  32. width0 := 1280; height0 := 1024;
  33. desc := "Graphics adapter view";
  34. NEW(canvas, backbuffer);
  35. canvas.SetFont(WMGraphics.GetDefaultFont());
  36. canvas.SaveState(state);
  37. factor := 1; intfactor := 1;
  38. fx := factor; fy := factor; inffx := 1 ; inffy := inffx;
  39. internnavig := FALSE;
  40. NEW(lock);
  41. onDrawn := NIL;
  42. currentZoomLevel := 0;
  43. SetZoomLevels(1280, 1024);
  44. END New;
  45. PROCEDURE SetZoomLevels(width, height : LONGINT);
  46. VAR i : LONGINT;
  47. BEGIN
  48. FOR i := 0 TO LEN(zoomLevel)-1 DO
  49. zoomLevel[i].width := (i + 1) * width;
  50. zoomLevel[i].height :=(i + 1) * height ;
  51. zoomLevel[i].x := (zoomLevel[i].width - width) DIV 2;
  52. zoomLevel[i].y := (zoomLevel[i].height - height) DIV 2;
  53. END;
  54. END SetZoomLevels;
  55. PROCEDURE SetZoomLevel(level, xg, yg : LONGINT);
  56. BEGIN
  57. IF (level < 0) THEN level := 0;
  58. ELSIF (level >= LEN(zoomLevel)) THEN level := LEN(zoomLevel)-1; END;
  59. SetRange(xg - zoomLevel[level].x, yg - zoomLevel[level].y, zoomLevel[level].width, zoomLevel[level].height, TRUE);
  60. currentZoomLevel := level;
  61. END SetZoomLevel;
  62. PROCEDURE ChangeZoom(dz, xg, yg : LONGINT);
  63. BEGIN
  64. SetZoomLevel(currentZoomLevel + dz, xg, yg);
  65. END ChangeZoom;
  66. PROCEDURE ReInit(width, height, format : LONGINT; onDrawn : OnDrawnProc);
  67. VAR tf : REAL;
  68. BEGIN
  69. SELF.onDrawn := onDrawn;
  70. IF (width # SELF.width) OR (height # SELF.height) THEN
  71. lock.Acquire;
  72. SELF.width := width; SELF.height := height;
  73. IF (width > 0) & (height > 0) THEN
  74. NEW(backbuffer);
  75. Raster.Create(backbuffer, width, height, Raster.DisplayFormat(format));
  76. deviceRect.l := 0; deviceRect.t := 0;
  77. deviceRect.r := width; deviceRect.b := height;
  78. width0 := width; height0 := height;
  79. NEW(canvas, backbuffer);
  80. canvas.SetFont(WMGraphics.GetDefaultFont());
  81. canvas.SaveState(state);
  82. factor := width / (range.r - range.l);
  83. tf := height / (range.b - range.t);
  84. IF factor > tf THEN factor := tf END;
  85. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  86. intfactor := factor;
  87. range.r := range.l + inffx * width;
  88. range.b := range.t + inffy * height;
  89. SetZoomLevels(width, height);
  90. ELSE
  91. canvas := NIL;
  92. END;
  93. lock.Release;
  94. END;
  95. END ReInit;
  96. PROCEDURE GetWMCoordinates*(CONST r : WMRectangles.Rectangle) : WMRectangles.Rectangle;
  97. VAR rect : WMRectangles.Rectangle;
  98. BEGIN
  99. rect.l := ENTIER(range.l + r.l * inffx);
  100. rect.r := ENTIER(range.l + r.r * inffx + 0.5);
  101. rect.t := ENTIER(range.t + r.t * inffy);
  102. rect.b := ENTIER(range.t + r.b * inffy + 0.5);
  103. RETURN rect;
  104. END GetWMCoordinates;
  105. PROCEDURE GetWMPosition(x, y : LONGINT; VAR xg, yg : LONGINT);
  106. BEGIN
  107. xg := ENTIER(range.l + x * inffx);
  108. yg := ENTIER(range.t + y * inffy);
  109. END GetWMPosition;
  110. (** Return the modifier keys that are pressed in the view *)
  111. PROCEDURE GetKeyState*(VAR state : SET);
  112. BEGIN
  113. state := {};
  114. END GetKeyState;
  115. (** Set the observed range. *)
  116. PROCEDURE SetRange*(x, y, w, h : REAL; showTransition : BOOLEAN);
  117. VAR
  118. sx, sy, sx2, sy2, dx, dy, dx2, dy2, x2, y2 : REAL;
  119. i, steps : LONGINT;
  120. CONST Steps = 16;
  121. PROCEDURE Set(x, y, w, h : REAL);
  122. VAR tf : REAL;
  123. BEGIN
  124. range.l := x;
  125. range.t := y;
  126. factor := (width) / w;
  127. tf := (height) / h;
  128. IF factor > tf THEN factor := tf END;
  129. fx := factor; fy := factor; inffx := 1 / factor; inffy := inffx;
  130. range.r := x + width * inffx;
  131. range.b := y + height * inffy;
  132. intfactor := factor;
  133. manager.RefreshView(SELF);
  134. IF onDrawn # NIL THEN onDrawn(); END;
  135. END Set;
  136. BEGIN
  137. IF w = 0 THEN w := 0.001 END;
  138. IF h = 0 THEN h := 0.001 END;
  139. IF showTransition THEN
  140. sx := range.l; sy := range.t;
  141. sx2 := range.r; sy2 := range.b;
  142. x2 := x + w; y2 := y + h;
  143. steps := Steps;
  144. IF (sx = x) & (sy = y) & (sx2 - sx = w) & (sy2- sy = h) THEN steps := 1 END;
  145. dx := (x - sx) / steps;
  146. dy := (y - sy) / steps;
  147. dx2 := (x2 - sx2) / steps;
  148. dy2 := (y2 - sy2) / steps;
  149. internnavig := TRUE; navig := TRUE;
  150. FOR i := 1 TO steps-1 DO
  151. Set(sx + dx * i, sy + dy * i, (sx2 + dx2 * i) - (sx + dx * i), (sy2 + dy2 * i) - (sy + dy * i))
  152. END;
  153. internnavig := FALSE; navig := FALSE
  154. END;
  155. Set(x, y, w, h)
  156. END SetRange;
  157. (** r in wm coordinates *)
  158. PROCEDURE Update*(r : WMRectangles.Rectangle; top : WMWindowManager.Window);
  159. BEGIN
  160. lock.Acquire;
  161. Draw(WMRectangles.ResizeRect(r, 1), top.prev);(* assuming the src-domain is only 1 *)
  162. lock.Release;
  163. END Update;
  164. PROCEDURE Refresh*(top : WMWindowManager.Window);
  165. BEGIN
  166. Update(WMRectangles.MakeRect(ENTIER(range.l)-1, ENTIER(range.t)-1, ENTIER(range.r) + 1, ENTIER(range.b) + 1), top)
  167. END Refresh;
  168. PROCEDURE DrawWindow(window : WMWindowManager.Window) : BOOLEAN;
  169. VAR title : Strings.String;
  170. BEGIN
  171. ASSERT(window # NIL);
  172. IF (window.isVisible & ~(WMWindowManager.FlagNavigation IN window.flags)) THEN
  173. title := window.GetTitle();
  174. RETURN (title = NIL) OR ((title^ # "Mouse Cursor"));
  175. ELSE
  176. RETURN FALSE;
  177. END;
  178. END DrawWindow;
  179. (* in wm coordinates *)
  180. PROCEDURE Draw(r : WMRectangles.Rectangle; top : WMWindowManager.Window);
  181. VAR cur : WMWindowManager.Window;
  182. wr, nr : WMRectangles.Rectangle;
  183. PROCEDURE InternalDraw(r : WMRectangles.Rectangle; cur : WMWindowManager.Window);
  184. VAR nr, cb, dsr : WMRectangles.Rectangle; width, height : LONGINT;
  185. BEGIN
  186. ASSERT(cur.isVisible);
  187. IF cur.useAlpha & (cur.prev # NIL) THEN Draw(r, cur.prev)
  188. ELSE
  189. WHILE (cur # NIL) DO (* draw r in wm coordinates in all the windows from cur to top *)
  190. IF DrawWindow(cur) THEN
  191. cb := cur.bounds;
  192. nr := r; WMRectangles.ClipRect(nr, cb);
  193. dsr.l := ENTIER((nr.l - range.l) * fx) ; dsr.t := ENTIER((nr.t - range.t) * fy);
  194. dsr.r := ENTIER((nr.r - range.l) * fx + 0.5); dsr.b := ENTIER((nr.b - range.t) * fy + 0.5);
  195. IF (~WMRectangles.RectEmpty(dsr)) & (WMRectangles.Intersect(dsr, deviceRect)) THEN
  196. canvas.SetClipRect(dsr); (* Set clip rect to dsr, clipped at current window *)
  197. (* range can not be factored out because of rounding *)
  198. canvas.ClipRectAsNewLimits(ENTIER((cur.bounds.l - range.l) * fx), ENTIER((cur.bounds.t - range.t) * fy));
  199. width := ENTIER((cb.r - range.l)* fx) - ENTIER((cb.l - range.l) * fx);
  200. height := ENTIER((cb.b - range.t) * fy) - ENTIER((cb.t - range.t) * fy);
  201. IF navig THEN
  202. cur.Draw(canvas, width, height, WMGraphics.ScaleBox);
  203. ELSE
  204. cur.Draw(canvas, width, height, WMGraphics.ScaleBilinear);
  205. END;
  206. canvas.RestoreState(state);
  207. END;
  208. END;
  209. cur := cur.next
  210. END;
  211. END
  212. END InternalDraw;
  213. BEGIN
  214. IF (canvas # NIL) THEN
  215. cur := top;
  216. IF (cur # NIL) & (~WMRectangles.RectEmpty(r)) THEN
  217. IF DrawWindow(cur) THEN
  218. wr := cur.bounds;
  219. IF ~WMRectangles.IsContained(wr, r) THEN
  220. IF WMRectangles.Intersect(r, wr) THEN
  221. (* r contains wr calculate r - wr and recursively call for resulting rectangles*)
  222. (* calculate top rectangle *)
  223. IF wr.t > r.t THEN WMRectangles.SetRect(nr, r.l, r.t, r.r, wr.t); Draw(nr, cur.prev) END;
  224. (* calculate bottom rectangle *)
  225. IF wr.b < r.b THEN WMRectangles.SetRect(nr, r.l, wr.b, r.r, r.b); Draw(nr, cur.prev) END;
  226. (* calculate left rectangle *)
  227. IF wr.l > r.l THEN WMRectangles.SetRect(nr, r.l, MAX(r.t, wr.t), wr.l, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  228. (* calculate left rectangle *)
  229. IF wr.r < r.r THEN WMRectangles.SetRect(nr, wr.r, MAX(r.t, wr.t), r.r, MIN(r.b, wr.b)); Draw(nr, cur.prev) END;
  230. (* calculate overlapping *)
  231. nr := r; WMRectangles.ClipRect(nr, wr);
  232. IF ~WMRectangles.RectEmpty(nr) THEN InternalDraw(nr, cur) END
  233. ELSE Draw(r, cur.prev)
  234. END
  235. ELSE InternalDraw(r, cur)
  236. END
  237. ELSE
  238. Draw(r, cur.prev);
  239. END;
  240. END;
  241. END;
  242. IF (onDrawn # NIL) THEN onDrawn(); END;
  243. END Draw;
  244. END ViewPort;
  245. TYPE
  246. Navigator = OBJECT(WMComponents.VisualComponent)
  247. VAR
  248. viewPort : ViewPort;
  249. selectedWindow : WMWindowManager.Window;
  250. timer : Kernel.Timer;
  251. alive, dead, refresh, doRefresh : BOOLEAN;
  252. offsetX, offsetY : LONGINT;
  253. lastX, lastY : LONGINT;
  254. PROCEDURE &Init*;
  255. VAR style : WMWindowManager.WindowStyle;
  256. BEGIN
  257. Init^;
  258. NEW(viewPort);
  259. NEW(timer);
  260. alive := TRUE; dead := FALSE; refresh := TRUE; doRefresh := FALSE;
  261. manager.AddView(viewPort);
  262. style := manager.GetStyle();
  263. IF (style # NIL) THEN
  264. fillColor.Set(style.desktopColor);
  265. END;
  266. END Init;
  267. PROCEDURE Finalize*;
  268. BEGIN
  269. Finalize^;
  270. BEGIN {EXCLUSIVE} alive := FALSE; END;
  271. BEGIN {EXCLUSIVE} AWAIT(dead); END;
  272. manager.RemoveView(viewPort);
  273. END Finalize;
  274. PROCEDURE PropertyChanged*(sender, data : ANY);
  275. BEGIN
  276. PropertyChanged^(sender, data);
  277. IF (data = bounds) THEN
  278. RecacheProperties;
  279. END;
  280. END PropertyChanged;
  281. PROCEDURE RecacheProperties*;
  282. BEGIN
  283. RecacheProperties^;
  284. viewPort.ReInit(bounds.GetWidth(), bounds.GetHeight(), Displays.color8888, Refresh);
  285. viewPort.manager.RefreshView(viewPort);
  286. Invalidate;
  287. END RecacheProperties;
  288. PROCEDURE PointerLeave*;
  289. BEGIN
  290. PointerLeave^;
  291. END PointerLeave;
  292. PROCEDURE PointerDown*(x, y: LONGINT; keys: SET);
  293. VAR xg, yg : LONGINT; rect : WMRectangles.Rectangle; title : Strings.String;
  294. BEGIN
  295. PointerDown^(x, y, keys);
  296. IF (0 IN keys) THEN
  297. viewPort.GetWMPosition(x, y, xg, yg);
  298. selectedWindow := manager.GetPositionOwner(xg, yg);
  299. IF (selectedWindow # NIL) THEN
  300. title := selectedWindow.GetTitle();
  301. IF (title # NIL) & ((title^ = "Old background") OR (title^ = "New background")) THEN selectedWindow := NIL; RETURN; END;
  302. manager.lock.AcquireRead;
  303. offsetX := (xg - selectedWindow.bounds.l);
  304. offsetY := (yg - selectedWindow.bounds.t);
  305. manager.lock.ReleaseRead;
  306. ELSE
  307. offsetX := 0; offsetY := 0;
  308. END;
  309. ELSIF (keys = {1}) THEN
  310. manager.GetPopulatedArea(rect);
  311. manager.lock.AcquireWrite;
  312. viewPort.SetRange(rect.l, rect.t, rect.r - rect.l, rect.b - rect.t, TRUE);
  313. manager.lock.ReleaseWrite;
  314. END;
  315. END PointerDown;
  316. PROCEDURE PointerMove*(x, y: LONGINT; keys: SET);
  317. VAR xg, yg : LONGINT;
  318. BEGIN
  319. lastX := x; lastY := y;
  320. PointerMove^(x, y, keys);
  321. IF (0 IN keys) THEN
  322. IF (selectedWindow # NIL) THEN
  323. viewPort.GetWMPosition(x, y, xg, yg);
  324. manager.SetWindowPos(selectedWindow, xg - offsetX, yg - offsetY);
  325. END;
  326. END;
  327. END PointerMove;
  328. PROCEDURE WheelMove*(dz: LONGINT);
  329. VAR xg, yg : LONGINT;
  330. BEGIN
  331. WheelMove^(dz);
  332. viewPort.GetWMPosition(lastX, lastY, xg, yg);
  333. viewPort.ChangeZoom(dz, xg, yg);
  334. END WheelMove;
  335. PROCEDURE PointerUp*(x, y: LONGINT; keys: SET);
  336. BEGIN
  337. PointerUp^(x, y, keys);
  338. selectedWindow := NIL;
  339. END PointerUp;
  340. PROCEDURE Refresh;
  341. BEGIN {EXCLUSIVE}
  342. refresh := TRUE;
  343. END Refresh;
  344. PROCEDURE Draw*(canvas : WMGraphics.Canvas);
  345. VAR r0, r1, res : WMWindowManager.RealRect; rect : WMRectangles.Rectangle;
  346. BEGIN
  347. IF (viewPort.backbuffer.width = bounds.GetWidth()) & (viewPort.backbuffer.height = bounds.GetHeight()) THEN
  348. canvas.DrawImage(0, 0, viewPort.backbuffer,WMGraphics.ModeSrcOverDst);
  349. ELSE
  350. canvas.ScaleImage(viewPort.backbuffer, WMRectangles.MakeRect(0, 0, viewPort.backbuffer.width, viewPort.backbuffer.height),
  351. WMRectangles.MakeRect(0, 0, bounds.GetWidth(), bounds.GetHeight()), WMGraphics.ModeSrcOverDst, 1)
  352. END;
  353. r0 := viewport.range;
  354. r1 := viewPort.range;
  355. IF (r0.l > r1.l) THEN res.l := r0.l; ELSE res.l := r1.l; END;
  356. IF (r0.t > r1.t) THEN res.t := r0.t; ELSE res.t := r1.t; END;
  357. IF (r0.r < r1.r) THEN res.r := r0.r; ELSE res.r := r1.r; END;
  358. IF (r0.b < r1.b) THEN res.b := r0.b; ELSE res.b := r1.b; END;
  359. rect := WMRectangles.MakeRect(ENTIER(viewPort.fx * (res.l - r1.l)), ENTIER(viewPort.fy * (res.t - r1.t)), ENTIER(viewPort.fx * (res.r - r1.l)), ENTIER(viewPort.fy * (res.b - r1.t)));
  360. WMGraphicUtilities.DrawRect(canvas, rect, LONGINT(0FF0000FFH), WMGraphics.ModeCopy);
  361. END Draw;
  362. BEGIN {ACTIVE}
  363. manager.lock.AcquireWrite;
  364. viewPort.SetRange(-1280, -1024, 2560, 2048, FALSE);
  365. manager.lock.ReleaseWrite;
  366. manager.RefreshView(viewPort);
  367. Invalidate;
  368. LOOP
  369. BEGIN {EXCLUSIVE}
  370. AWAIT(refresh OR ~alive);
  371. doRefresh := refresh;
  372. refresh := FALSE;
  373. END;
  374. timer.Sleep(30);
  375. IF ~alive THEN EXIT; END;
  376. IF doRefresh THEN
  377. doRefresh := FALSE;
  378. Invalidate;
  379. END;
  380. END;
  381. BEGIN {EXCLUSIVE} dead := TRUE; END;
  382. END Navigator;
  383. TYPE
  384. Window = OBJECT(WMComponents.FormWindow)
  385. PROCEDURE Close*;
  386. BEGIN
  387. Close^;
  388. window := NIL;
  389. END Close;
  390. END Window;
  391. VAR
  392. manager : WMWindowManager.WindowManager;
  393. viewport : WMWindowManager.ViewPort;
  394. window : Window;
  395. PROCEDURE GenNavigator*() : XML.Element;
  396. VAR n : Navigator;
  397. BEGIN
  398. NEW(n); RETURN n;
  399. END GenNavigator;
  400. PROCEDURE Init;
  401. BEGIN
  402. manager := WMWindowManager.GetDefaultManager();
  403. viewport := WMWindowManager.GetDefaultView();
  404. END Init;
  405. PROCEDURE Open*;
  406. VAR n : Navigator;
  407. BEGIN {EXCLUSIVE}
  408. IF (window = NIL) THEN
  409. NEW(n); n.alignment.Set(WMComponents.AlignClient);
  410. NEW(window, 400, 200, TRUE);
  411. window.SetContent(n);
  412. WMWindowManager.ExtAddViewBoundWindow(window, 20, 20, NIL,
  413. {WMWindowManager.FlagFrame, WMWindowManager.FlagStayOnTop, WMWindowManager.FlagNavigation, WMWindowManager.FlagHidden});
  414. END;
  415. END Open;
  416. PROCEDURE Close*;
  417. BEGIN {EXCLUSIVE}
  418. IF (window # NIL) THEN window.Close; window := NIL; END;
  419. END Close;
  420. BEGIN
  421. Modules.InstallTermHandler(Close);
  422. Init;
  423. END WMNavigator.
  424. WMNavigator.Open ~
  425. WMNavigator.Close ~
  426. System.Free WMNavigator ~