SimpleGui.Mod 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. MODULE SimpleGui;
  2. IMPORT G := Graph, Strings, Out;
  3. TYPE
  4. Widget* = POINTER TO WidgetDesc;
  5. Message* = RECORD END;
  6. DrawMsg* = RECORD(Message) x*, y*, w*, h*: INTEGER END;
  7. MouseMoveMsg* = RECORD(Message) x*, y*: INTEGER END;
  8. MouseEnterMsg* = RECORD(Message) END;
  9. MouseLeaveMsg* = RECORD(Message) END;
  10. Handler* = PROCEDURE (c: Widget; VAR msg: Message);
  11. WidgetDesc* = RECORD
  12. x*, y*, w*, h*: INTEGER;
  13. bgColor*, fgColor*: G.Color;
  14. body*: Widget;
  15. next*: Widget;
  16. handle*: Handler;
  17. END;
  18. Panel* = POINTER TO PanelDesc;
  19. PanelDesc* = RECORD(WidgetDesc) END;
  20. Form* = POINTER TO FormDesc;
  21. FormDesc* = RECORD(PanelDesc) END;
  22. Button* = POINTER TO ButtonDesc;
  23. ButtonDesc* = RECORD(WidgetDesc)
  24. caption*: ARRAY 64 OF CHAR;
  25. underMouse*: BOOLEAN
  26. END;
  27. VAR
  28. Done*: BOOLEAN; (** FALSE after a failed opration and before the next Init *)
  29. forms*: Form;
  30. font*: G.Font;
  31. quit: BOOLEAN; (** Main loop in procedure Run ends when TRUE *)
  32. widgetUnderMouse: Widget;
  33. (** Widget **)
  34. PROCEDURE FindUnderMouseInList(x, y: INTEGER; c: Widget): Widget;
  35. BEGIN
  36. WHILE (c # NIL) &
  37. ~((c.x <= x) & (x < c.x + c.w) &
  38. (c.y <= y) & (y < c.y + c.h))
  39. DO c := c.next
  40. END
  41. RETURN c END FindUnderMouseInList;
  42. PROCEDURE WidgetOnMouseEnter*(c: Widget);
  43. VAR msg: MouseEnterMsg;
  44. BEGIN c.handle(c, msg)
  45. END WidgetOnMouseEnter;
  46. PROCEDURE WidgetOnMouseLeave*(c: Widget);
  47. VAR msg: MouseLeaveMsg;
  48. BEGIN c.handle(c, msg)
  49. END WidgetOnMouseLeave;
  50. PROCEDURE WidgetOnMouseMove*(c: Widget; x, y: INTEGER);
  51. VAR msg: MouseMoveMsg;
  52. BEGIN
  53. IF (widgetUnderMouse = NIL) OR (c # widgetUnderMouse) THEN
  54. IF widgetUnderMouse # NIL THEN WidgetOnMouseLeave(widgetUnderMouse) END;
  55. widgetUnderMouse := c;
  56. WidgetOnMouseEnter(widgetUnderMouse)
  57. END;
  58. msg.x := x; msg.y := y;
  59. c.handle(c, msg)
  60. END WidgetOnMouseMove;
  61. PROCEDURE WidgetHandleMouseMove*(c: Widget; x, y: INTEGER);
  62. VAR p: Widget;
  63. BEGIN
  64. p := FindUnderMouseInList(x, y, c.body);
  65. IF p # NIL THEN
  66. WidgetHandleMouseMove(p, x - p.x, y - p.y)
  67. ELSE
  68. WidgetOnMouseMove(c, x, y)
  69. END
  70. END WidgetHandleMouseMove;
  71. PROCEDURE WidgetHandler*(c: Widget; VAR msg: Message);
  72. VAR x, y: INTEGER;
  73. BEGIN
  74. IF msg IS DrawMsg THEN
  75. x := msg(DrawMsg).x; y := msg(DrawMsg).y;
  76. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor);
  77. G.Rect(x, y, x + c.w - 1, y + c.h - 1, c.fgColor);
  78. G.Rect(x + 2, y + 2, x + c.w - 3, y + c.h - 3, c.fgColor)
  79. END
  80. END WidgetHandler;
  81. PROCEDURE DrawWidget*(c: Widget; x, y, w, h: INTEGER);
  82. VAR M: DrawMsg;
  83. BEGIN
  84. M.x := x; M.y := y; M.w := w; M.h := h;
  85. c.handle(c, M)
  86. END DrawWidget;
  87. PROCEDURE DrawBody*(c: Widget; x, y, w, h: INTEGER);
  88. VAR p: Widget;
  89. x2, y2, w2, h2: INTEGER;
  90. BEGIN
  91. p := c.body;
  92. WHILE p # NIL DO
  93. x2 := x + p.x; y2 := y + p.y;
  94. w2 := w - p.x; h2 := h - p.y;
  95. DrawWidget(p, x2, y2, w2, h2);
  96. p := p.next
  97. END
  98. END DrawBody;
  99. PROCEDURE InitWidget*(c: Widget; w, h: INTEGER);
  100. BEGIN c.x := 0; c.y := 0; c.w := w; c.h := h;
  101. G.MakeCol(c.bgColor, 180, 180, 180);
  102. G.MakeCol(c.fgColor, 0, 0, 0);
  103. c.handle := WidgetHandler;
  104. c.body := NIL; c.next := NIL
  105. END InitWidget;
  106. PROCEDURE Put*(c, where: Widget; x, y: INTEGER);
  107. BEGIN
  108. c.x := x; c.y := y;
  109. c.next := where.body;
  110. where.body := c
  111. END Put;
  112. (** Panel **)
  113. PROCEDURE PanelHandler*(c: Widget; VAR msg: Message);
  114. VAR x, y: INTEGER;
  115. BEGIN
  116. IF msg IS DrawMsg THEN
  117. x := msg(DrawMsg).x; y := msg(DrawMsg).y;
  118. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor);
  119. DrawBody(c, x, y, c.w, c.h)
  120. ELSE WidgetHandler(c, msg)
  121. END
  122. END PanelHandler;
  123. PROCEDURE InitPanel*(c: Panel; w, h: INTEGER);
  124. BEGIN InitWidget(c, w, h);
  125. c.handle := PanelHandler
  126. END InitPanel;
  127. PROCEDURE NewPanel*(x, y, w, h: INTEGER): Panel;
  128. VAR c: Panel;
  129. BEGIN NEW(c); InitPanel(c, w, h)
  130. RETURN c END NewPanel;
  131. (** Form **)
  132. PROCEDURE DrawForm*(c: Form);
  133. BEGIN
  134. G.FillRect(c.x, c.y, c.x + c.w - 1, c.y + c.h - 1, c.bgColor);
  135. DrawBody(c, c.x, c.y, c.w, c.h)
  136. END DrawForm;
  137. PROCEDURE FormHandler*(c: Widget; VAR msg: Message);
  138. BEGIN WidgetHandler(c, msg)
  139. END FormHandler;
  140. PROCEDURE InitForm*(c: Form; x, y, w, h: INTEGER);
  141. BEGIN InitPanel(c, w, h);
  142. c.x := x; c.y := y;
  143. c.handle := FormHandler;
  144. c.next := forms; forms := c
  145. END InitForm;
  146. PROCEDURE NewForm*(x, y, w, h: INTEGER): Form;
  147. VAR c: Form;
  148. BEGIN NEW(c); InitForm(c, x, y, w, h);
  149. RETURN c END NewForm;
  150. (** Button **)
  151. PROCEDURE DrawButton*(c: Button; x, y, w, h: INTEGER);
  152. VAR cw, ch, tw: INTEGER;
  153. BEGIN
  154. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor);
  155. G.Rect(x, y, x + c.w - 1, y + c.h - 1, c.fgColor);
  156. IF ~c(Button).underMouse THEN
  157. G.Rect(x, y, x + c.w - 2, y + c.h - 2, c.fgColor)
  158. END;
  159. G.GetMonoFontSize(font, cw, ch);
  160. tw := Strings.Length(c.caption) * cw;
  161. G.DrawString(c.caption, x + (c.w - tw) DIV 2,
  162. y + (c.h - ch) DIV 2, font, c.fgColor)
  163. END DrawButton;
  164. PROCEDURE ButtonHandler*(c: Widget; VAR msg: Message);
  165. VAR b: Button;
  166. BEGIN b := c(Button);
  167. IF msg IS DrawMsg THEN
  168. DrawButton(b, msg(DrawMsg).x, msg(DrawMsg).y,
  169. msg(DrawMsg).w, msg(DrawMsg).h)
  170. ELSIF msg IS MouseEnterMsg THEN b.underMouse := TRUE
  171. ELSIF msg IS MouseLeaveMsg THEN b.underMouse := FALSE
  172. ELSE WidgetHandler(c, msg)
  173. END
  174. END ButtonHandler;
  175. PROCEDURE InitButton*(c: Button; where: Widget;
  176. x, y, w, h: INTEGER; caption: ARRAY OF CHAR);
  177. BEGIN InitWidget(c, w, h);
  178. Strings.Copy(caption, c.caption);
  179. c.underMouse := FALSE;
  180. c.handle := ButtonHandler;
  181. Put(c, where, x, y)
  182. END InitButton;
  183. PROCEDURE NewButton*(where: Widget; x, y, w, h: INTEGER; caption: ARRAY OF CHAR): Button;
  184. VAR c: Button;
  185. BEGIN NEW(c); InitButton(c, where, x, y, w, h, caption)
  186. RETURN c END NewButton;
  187. (** General **)
  188. PROCEDURE DrawAll*;
  189. VAR c: Widget;
  190. BEGIN
  191. c := forms;
  192. WHILE c # NIL DO
  193. DrawForm(c(Form));
  194. c := c.next
  195. END;
  196. G.Flip
  197. END DrawAll;
  198. PROCEDURE HandleMouseMove(VAR e: G.Event);
  199. VAR c: Widget;
  200. BEGIN
  201. c := FindUnderMouseInList(e.x, e.y, forms);
  202. IF c # NIL THEN
  203. WidgetHandleMouseMove(c, e.x - c.x, e.y - c.y)
  204. END
  205. END HandleMouseMove;
  206. PROCEDURE HandleEvent(VAR e: G.Event);
  207. BEGIN
  208. IF e.type = G.quit THEN quit := TRUE
  209. ELSIF e.type = G.mouseMove THEN HandleMouseMove(e)
  210. END
  211. END HandleEvent;
  212. PROCEDURE Run*;
  213. VAR e: G.Event;
  214. BEGIN
  215. quit := FALSE;
  216. REPEAT
  217. WHILE G.HasEvents() DO
  218. G.WaitEvent(e);
  219. HandleEvent(e)
  220. END;
  221. DrawAll
  222. UNTIL quit
  223. END Run;
  224. PROCEDURE Init*;
  225. BEGIN
  226. forms := NIL;
  227. font := G.LoadFont('Data/Fonts/Main');
  228. IF font = NIL THEN Out.String('SimpleGui: could not load font.'); Out.Ln END;
  229. Done := font # NIL;
  230. widgetUnderMouse := NIL
  231. END Init;
  232. END SimpleGui.