Gui.Mod 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. MODULE Gui;
  2. IMPORT G := Graph, Strings, Out;
  3. CONST
  4. (* Widget.state set members *)
  5. hover* = 0;
  6. down* = 1;
  7. focus* = 2;
  8. TYPE
  9. Caption* = POINTER TO CaptionDesc;
  10. CaptionDesc* = RECORD
  11. s*: ARRAY 100 OF CHAR
  12. END;
  13. DrawHandler* = PROCEDURE (W: Widget; x, y: INTEGER);
  14. MouseMoveHandler* = PROCEDURE (W: Widget; x, y, btn: INTEGER);
  15. MouseDownHandler* = PROCEDURE (W: Widget; x, y, btn: INTEGER);
  16. MouseUpHandler* = PROCEDURE (W: Widget; x, y, btn: INTEGER);
  17. ClickHandler* = PROCEDURE (W: Widget);
  18. Message* = POINTER TO MsgDesc;
  19. MsgDesc* = RECORD END;
  20. Handler* = PROCEDURE (W: Widget; VAR msg: Message);
  21. Widget* = POINTER TO WidgetDesc;
  22. WidgetDesc* = RECORD
  23. x*, y*, w*, h*: INTEGER;
  24. tag*: INTEGER;
  25. state*: SET;
  26. visible: BOOLEAN;
  27. enabled: BOOLEAN;
  28. body*: Widget;
  29. text*: Caption;
  30. bmp*: G.Bitmap;
  31. parent*: Widget;
  32. prev*, next*: Widget;
  33. (* Event Handlers *)
  34. onMouseMove*: MouseMoveHandler;
  35. onMouseDown*: MouseDownHandler;
  36. onMouseUp*: MouseUpHandler;
  37. onClick*: ClickHandler;
  38. (* Message Handler *)
  39. handle*: Handler;
  40. draw*: DrawHandler
  41. END;
  42. Window* = POINTER TO WindowDesc;
  43. WindowDesc* = RECORD(WidgetDesc)
  44. win*: G.Window;
  45. curMouseDownWidget*: Widget (* Widget under mouse down event is saved here *)
  46. END;
  47. VAR
  48. Done*: BOOLEAN;
  49. exitRunLoop: BOOLEAN; (* See procedure Run *)
  50. font: G.Font;
  51. newWindowSettings: SET;
  52. globalWin: Window; (* !FIXME *)
  53. (* Widget *)
  54. PROCEDURE SetOnMouseMove*(W: Widget; handler: MouseMoveHandler);
  55. BEGIN
  56. W.onMouseMove := handler
  57. END SetOnMouseMove;
  58. PROCEDURE SetOnMouseDown*(W: Widget; handler: MouseDownHandler);
  59. BEGIN
  60. W.onMouseDown := handler
  61. END SetOnMouseDown;
  62. PROCEDURE SetOnMouseUp*(W: Widget; handler: MouseUpHandler);
  63. BEGIN
  64. W.onMouseUp := handler
  65. END SetOnMouseUp;
  66. PROCEDURE SetOnClick*(W: Widget; handler: ClickHandler);
  67. BEGIN
  68. W.onClick := handler;
  69. END SetOnClick;
  70. PROCEDURE InitWidget*(w: Widget);
  71. BEGIN
  72. w.x := 0; w.y := 0; w.w := 24; w.h := 24;
  73. w.tag := 0;
  74. w.state := {};
  75. w.visible := TRUE;
  76. w.enabled := TRUE;
  77. w.draw := NIL;
  78. w.onMouseMove := NIL;
  79. w.onMouseDown := NIL;
  80. w.onMouseUp := NIL;
  81. w.onClick := NIL;
  82. (* Замок *)
  83. NEW(w.body); w.body.prev := w.body; w.body.next := w.body
  84. END InitWidget;
  85. PROCEDURE SetText*(w: Widget; s: ARRAY OF CHAR);
  86. BEGIN
  87. IF w.text = NIL THEN NEW(w.text) END;
  88. Strings.Copy(s, w.text.s)
  89. END SetText;
  90. PROCEDURE Place*(where, what: Widget; x, y: INTEGER);
  91. BEGIN
  92. what.x := x; what.y := y;
  93. (* Добавление в кольцо с замком *)
  94. what.prev := where.body.prev;
  95. what.next := where.body;
  96. where.body.prev.next := what;
  97. where.body.prev := what
  98. END Place;
  99. (* Window *)
  100. PROCEDURE NewWindowSettings*(settings: SET);
  101. BEGIN
  102. newWindowSettings := settings
  103. END NewWindowSettings;
  104. PROCEDURE DrawWidget(W: Widget; x, y: INTEGER);
  105. BEGIN
  106. W.draw(W, x + W.x, y + W.y)
  107. END DrawWidget;
  108. PROCEDURE DrawBody*(W: Widget; x, y: INTEGER);
  109. VAR p: Widget;
  110. BEGIN
  111. p := W.body.next;
  112. WHILE p # W.body DO
  113. DrawWidget(p, x, y);
  114. p := p.next
  115. END
  116. END DrawBody;
  117. PROCEDURE DrawWindow*(W: Widget; x, y: INTEGER);
  118. VAR c: G.Color;
  119. w, h: INTEGER;
  120. BEGIN
  121. G.MakeCol(c, 212, 208, 200);
  122. G.ClearToColor(c);
  123. DrawBody(W, x, y)
  124. END DrawWindow;
  125. PROCEDURE InitWindow*(win: Window; w, h: INTEGER);
  126. BEGIN
  127. InitWidget(win);
  128. win.win := G.NewWindow(-1, -1, w, h,
  129. 'Window', newWindowSettings);
  130. win.x := 0; win.y := 0;
  131. win.w := win.win.w; win.h := win.win.h;
  132. win.curMouseDownWidget := NIL;
  133. win.draw := DrawWindow
  134. END InitWindow;
  135. PROCEDURE NewWindow*(w, h: INTEGER): Window;
  136. VAR win: Window;
  137. BEGIN
  138. NEW(win);
  139. InitWindow(win, w, h);
  140. globalWin := win
  141. RETURN win END NewWindow;
  142. (* Draw *)
  143. PROCEDURE DrawAll;
  144. BEGIN
  145. globalWin.draw(globalWin, 0, 0);
  146. G.Flip;
  147. G.Delay(1)
  148. END DrawAll;
  149. (* Fonts *)
  150. PROCEDURE GetFont*(W: Widget): G.Font;
  151. RETURN font END GetFont;
  152. (* General *)
  153. PROCEDURE TriggerOnMouseMove*(W: Widget; x, y, btn: INTEGER);
  154. BEGIN
  155. IF (W # NIL) & (W.onMouseMove # NIL) THEN
  156. W.onMouseMove(W, x, y, btn)
  157. END
  158. END TriggerOnMouseMove;
  159. PROCEDURE TriggerOnMouseDown*(W: Widget; x, y, btn: INTEGER);
  160. BEGIN
  161. IF (W # NIL) & (W.onMouseDown # NIL) THEN
  162. W.onMouseDown(W, x, y, btn)
  163. END
  164. END TriggerOnMouseDown;
  165. PROCEDURE TriggerOnMouseUp*(W: Widget; x, y, btn: INTEGER);
  166. BEGIN
  167. IF (W # NIL) & (W.onMouseUp # NIL) THEN
  168. W.onMouseUp(W, x, y, btn)
  169. END
  170. END TriggerOnMouseUp;
  171. PROCEDURE TriggerOnClick*(W: Widget);
  172. BEGIN
  173. IF (W # NIL) & (W.onClick # NIL) THEN
  174. W.onClick(W)
  175. END
  176. END TriggerOnClick;
  177. PROCEDURE FindWidgetUnderMouse*(W: Widget; VAR x, y: INTEGER): Widget;
  178. VAR p: Widget;
  179. BEGIN
  180. IF W = NIL THEN p := W
  181. ELSIF W.body # NIL THEN
  182. p := W.body.prev;
  183. WHILE (p # W.body) &
  184. ~((p.x <= x) & (x < p.x + p.w) &
  185. (p.y <= y) & (y < p.y + p.h))
  186. DO p := p.prev
  187. END;
  188. IF p = W.body THEN p := W
  189. ELSE DEC(x, p.x); DEC(y, p.y);
  190. p := FindWidgetUnderMouse(p, x, y)
  191. END
  192. ELSE p := W
  193. END
  194. RETURN p END FindWidgetUnderMouse;
  195. (** Input: (x; y) relative to window.
  196. Output: (x; y) relative to widget. *)
  197. PROCEDURE WindowToWidgetXY*(W: Widget; VAR x, y: INTEGER);
  198. BEGIN
  199. WHILE (W # NIL) & ~(W IS Window) DO
  200. DEC(x, W.x); DEC(y, W.y);
  201. W := W.parent
  202. END
  203. END WindowToWidgetXY;
  204. PROCEDURE HandleMouseMoveEvent*(e: G.Event);
  205. VAR W: Widget;
  206. x, y: INTEGER;
  207. BEGIN
  208. x := e.x; y := e.y;
  209. IF globalWin.curMouseDownWidget # NIL THEN
  210. W := globalWin.curMouseDownWidget;
  211. WindowToWidgetXY(W, x, y);
  212. IF (x >= 0) & (y >= 0) & (W.w > x) & (W.h > y) & (1 IN e.buttons) THEN
  213. INCL(W.state, down)
  214. ELSE EXCL(W.state, down)
  215. END
  216. ELSE
  217. W := FindWidgetUnderMouse(globalWin, x, y);
  218. END;
  219. IF W # NIL THEN
  220. INCL(W.state, hover); (* Mark button as being mouse-hovered *) (*!FIXME not done yet*)
  221. TriggerOnMouseMove(W, x, y, e.button)
  222. END
  223. END HandleMouseMoveEvent;
  224. PROCEDURE HandleMouseDownEvent*(e: G.Event);
  225. VAR W: Widget;
  226. x, y: INTEGER;
  227. BEGIN
  228. x := e.x; y := e.y;
  229. W := FindWidgetUnderMouse(globalWin, x, y);
  230. IF W # NIL THEN
  231. IF e.button = 1 THEN
  232. INCL(W.state, down) (* Mark button as being left-mouse-button-down *)
  233. END;
  234. globalWin.curMouseDownWidget := W; (* Save for future mouse up event *)
  235. TriggerOnMouseDown(W, x, y, e.button)
  236. END
  237. END HandleMouseDownEvent;
  238. PROCEDURE HandleMouseUpEvent*(e: G.Event);
  239. VAR W: Widget;
  240. x, y: INTEGER;
  241. BEGIN
  242. x := e.x; y := e.y;
  243. W := globalWin.curMouseDownWidget;
  244. globalWin.curMouseDownWidget := NIL;
  245. IF W # NIL THEN
  246. WindowToWidgetXY(W, x, y);
  247. EXCL(W.state, down);
  248. TriggerOnMouseUp(W, x, y, e.button);
  249. IF (x >= 0) & (y >= 0) & (W.w > x) & (W.h > y) & (e.button = 1) THEN
  250. TriggerOnClick(W)
  251. END
  252. END
  253. END HandleMouseUpEvent;
  254. PROCEDURE HandleEvent(e: G.Event);
  255. BEGIN
  256. IF e.type = G.mouseMove THEN
  257. HandleMouseMoveEvent(e)
  258. ELSIF e.type = G.mouseDown THEN
  259. HandleMouseDownEvent(e)
  260. ELSIF e.type = G.mouseUp THEN
  261. HandleMouseUpEvent(e)
  262. ELSIF e.type = G.keyDown THEN
  263. IF e.key = G.kEsc THEN exitRunLoop := TRUE END;
  264. ELSIF e.type = G.quit THEN
  265. exitRunLoop := TRUE
  266. END
  267. END HandleEvent;
  268. PROCEDURE Run*;
  269. VAR e: G.Event;
  270. BEGIN
  271. exitRunLoop := FALSE;
  272. REPEAT
  273. WHILE G.HasEvents() DO
  274. G.WaitEvent(e);
  275. HandleEvent(e)
  276. END;
  277. DrawAll
  278. UNTIL exitRunLoop
  279. END Run;
  280. PROCEDURE Init*;
  281. BEGIN
  282. G.Settings(0, 0, {G.manual});
  283. G.Init;
  284. IF G.Done THEN
  285. font := G.LoadFont('../Data/Fonts/Main');
  286. IF font = NIL THEN
  287. Out.String('Gui: Could not load font.'); Out.Ln;
  288. Done := FALSE
  289. END
  290. ELSE Done := FALSE
  291. END
  292. END Init;
  293. PROCEDURE Close*;
  294. BEGIN
  295. G.Close
  296. END Close;
  297. BEGIN
  298. Done := TRUE
  299. END Gui.