SimpleGui.Mod 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. MODULE SimpleGui;
  2. IMPORT G := Graph, Strings, Out;
  3. TYPE
  4. Widget* = POINTER TO WidgetDesc;
  5. Message* = RECORD END;
  6. PutMsg* = RECORD(Message) what*: Widget; x*, y*: INTEGER END;
  7. DrawMsg* = RECORD(Message) x*, y*, w*, h*: INTEGER END;
  8. MouseMoveMsg* = RECORD(Message) x*, y*, btn*: INTEGER END;
  9. MouseDownMsg* = RECORD(Message) x*, y*, btn*: INTEGER END;
  10. MouseUpMsg* = RECORD(Message) x*, y*, btn*: INTEGER END;
  11. MouseEnterMsg* = RECORD(Message) END;
  12. MouseLeaveMsg* = RECORD(Message) END;
  13. ClickMsg* = RECORD(Message) END;
  14. GetFocusMsg* = RECORD(Message) END;
  15. LostFocusMsg* = RECORD(Message) END;
  16. KeyDownMsg* = RECORD(Message) key*: INTEGER END;
  17. KeyUpMsg* = RECORD(Message) key*: INTEGER END;
  18. CharMsg* = RECORD(Message)
  19. key*: INTEGER;
  20. ch*: CHAR;
  21. mod*: SET;
  22. repeat*: BOOLEAN
  23. END;
  24. Handler* = PROCEDURE (c: Widget; VAR msg: Message);
  25. WidgetDesc* = RECORD
  26. x*, y*, w*, h*: INTEGER;
  27. bgColor*, fgColor*: G.Color;
  28. focusable*: BOOLEAN; (** TRUE if widget can get focus *)
  29. focused*: BOOLEAN; (** TRUE if this widget is globally in focus *)
  30. hovered*: BOOLEAN; (** TRUE if mouse pointer is over the widget *)
  31. pressed*: BOOLEAN; (** TRUE if widget is held down with LMB *)
  32. body*: Widget; (** A ring of widgets that this widget contains *)
  33. parent*: Widget; (** A widget that this widget is contained in *)
  34. prev*, next*: Widget;
  35. handle*: Handler;
  36. onPaint*: PROCEDURE (c: Widget; x, y, w, h: INTEGER);
  37. onMouseDown*: PROCEDURE (c: Widget; x, y, btn: INTEGER);
  38. onMouseUp*: PROCEDURE (c: Widget; x, y, btn: INTEGER);
  39. onMouseMove*: PROCEDURE (c: Widget; x, y, btn: INTEGER);
  40. onMouseEnter*: PROCEDURE (c: Widget);
  41. onMouseLeave*: PROCEDURE (c: Widget);
  42. onClick*: PROCEDURE (c: Widget);
  43. onKeyDown*: PROCEDURE (c: Widget; key: INTEGER);
  44. onKeyUp*: PROCEDURE (c: Widget; key: INTEGER);
  45. onChar*: PROCEDURE (c: Widget; key: INTEGER; ch: CHAR; mod: SET; repeat: BOOLEAN);
  46. END;
  47. App* = POINTER TO AppDesc;
  48. AppDesc* = RECORD(WidgetDesc) END;
  49. Form* = POINTER TO FormDesc;
  50. FormDesc* = RECORD(WidgetDesc) END;
  51. Panel* = POINTER TO PanelDesc;
  52. PanelDesc* = RECORD(WidgetDesc)
  53. noBg*: BOOLEAN
  54. END;
  55. Button* = POINTER TO ButtonDesc;
  56. ButtonDesc* = RECORD(WidgetDesc)
  57. caption*: ARRAY 64 OF CHAR
  58. END;
  59. Edit* = POINTER TO EditDesc;
  60. EditDesc* = RECORD(WidgetDesc)
  61. text*: ARRAY 256 OF CHAR;
  62. len*: INTEGER; (** Length of text in characters *)
  63. pos*: INTEGER; (** Position of text carret, in range [0; len] *)
  64. off*: INTEGER (** Used to slide text that does not fit, normal is 0 *)
  65. END;
  66. ScrollBar* = POINTER TO ScrollBarDesc;
  67. ScrollBarDesc* = RECORD(WidgetDesc)
  68. vertical*: BOOLEAN; (** TRUE for vertical scroll, FALSE for horizontal *)
  69. min*, max*: INTEGER;
  70. value*: INTEGER; (** The position of the scroll, in range [min; max] *)
  71. inc*, bigInc*: INTEGER; (** A single increment of value, and a big one *)
  72. btnSize*: INTEGER; (** Width or height (depending on vertical) of buttons *)
  73. handlePos*, handleSize*: INTEGER; (** Size and position of handle, px *)
  74. handlePressed*: BOOLEAN;
  75. handlePressPos*: INTEGER; (** Where handle was pressed, offset in px *)
  76. btnPressed*: INTEGER; (** 0-nothing, 1-less btn, 2-more btn, 3-handle *)
  77. onScroll*: PROCEDURE (c: ScrollBar; value: INTEGER);
  78. END;
  79. ScrollBox* = POINTER TO ScrollBoxDesc;
  80. ScrollBoxDesc* = RECORD(WidgetDesc)
  81. noBg*: BOOLEAN;
  82. outer*, inner*: Panel;
  83. scbHoriz*, scbVert*: ScrollBar
  84. END;
  85. VAR
  86. Done*: BOOLEAN; (** FALSE after a failed opration and before the next Init *)
  87. app*: App;
  88. focusedWidget*: Widget; (** The widget with focus = TRUE *)
  89. font*: G.Font;
  90. quit: BOOLEAN; (** Main loop in procedure Run ends when TRUE *)
  91. hoveredWidget: Widget;
  92. pressedWidget: Widget;
  93. pressedX, pressedY: INTEGER;
  94. mouseCursor: G.Bitmap;
  95. mouseX, mouseY: INTEGER;
  96. (** Widget **)
  97. PROCEDURE FindHoveredInRing(list: Widget; x, y: INTEGER;
  98. forMouseDown: BOOLEAN): Widget;
  99. VAR c: Widget;
  100. BEGIN
  101. IF list # NIL THEN
  102. c := list.prev;
  103. WHILE (c # NIL) &
  104. ~((c.x <= x) & (x < c.x + c.w) &
  105. (c.y <= y) & (y < c.y + c.h))
  106. DO
  107. IF c = list THEN c := NIL ELSE c := c.prev END
  108. END;
  109. IF forMouseDown & (c # NIL) THEN
  110. INC(pressedX, c.x); INC(pressedY, c.y)
  111. END
  112. ELSE c := NIL
  113. END
  114. RETURN c END FindHoveredInRing;
  115. PROCEDURE WidgetOnMouseEnter*(c: Widget);
  116. VAR msg: MouseEnterMsg;
  117. BEGIN
  118. IF pressedWidget = c THEN c.pressed := TRUE END;
  119. c.hovered := TRUE;
  120. c.handle(c, msg)
  121. END WidgetOnMouseEnter;
  122. PROCEDURE WidgetOnMouseLeave*(c: Widget);
  123. VAR msg: MouseLeaveMsg;
  124. BEGIN
  125. c.hovered := FALSE;
  126. c.pressed := FALSE;
  127. c.handle(c, msg)
  128. END WidgetOnMouseLeave;
  129. PROCEDURE WidgetOnMouseMove*(c: Widget; x, y, btn: INTEGER);
  130. VAR msg: MouseMoveMsg;
  131. BEGIN
  132. IF (0 <= x) & (x < c.w) & (0 <= y) & (y < c.h) THEN
  133. IF c # hoveredWidget THEN
  134. IF hoveredWidget # NIL THEN WidgetOnMouseLeave(hoveredWidget) END;
  135. hoveredWidget := c;
  136. WidgetOnMouseEnter(hoveredWidget)
  137. END
  138. ELSIF c = hoveredWidget THEN
  139. WidgetOnMouseLeave(c);
  140. hoveredWidget := NIL
  141. END;
  142. msg.x := x; msg.y := y; msg.btn := btn;
  143. c.handle(c, msg);
  144. IF c.onMouseMove # NIL THEN c.onMouseMove(c, x, y, btn) END
  145. END WidgetOnMouseMove;
  146. PROCEDURE WidgetHandleMouseMove*(c: Widget; x, y, btn: INTEGER);
  147. VAR p: Widget;
  148. BEGIN
  149. IF pressedWidget # NIL THEN
  150. WidgetOnMouseMove(pressedWidget, x - pressedX, y - pressedY, btn)
  151. ELSE
  152. p := FindHoveredInRing(c.body, x, y, FALSE);
  153. IF p # NIL THEN
  154. WidgetHandleMouseMove(p, x - p.x, y - p.y, btn)
  155. ELSE
  156. WidgetOnMouseMove(c, x, y, btn)
  157. END
  158. END
  159. END WidgetHandleMouseMove;
  160. PROCEDURE Resize*(c: Widget; w, h: INTEGER);
  161. BEGIN
  162. c.w := w;
  163. c.h := h
  164. END Resize;
  165. PROCEDURE Focus*(c: Widget);
  166. VAR get: GetFocusMsg;
  167. lost: LostFocusMsg;
  168. BEGIN
  169. IF c.focusable THEN
  170. IF focusedWidget # NIL THEN
  171. focusedWidget.focused := FALSE;
  172. focusedWidget.handle(focusedWidget, lost)
  173. END;
  174. c.focused := TRUE;
  175. focusedWidget := c;
  176. focusedWidget.handle(focusedWidget, get)
  177. END
  178. END Focus;
  179. PROCEDURE Detach*(c: Widget);
  180. VAR p: Widget;
  181. BEGIN
  182. IF c.parent # NIL THEN
  183. IF c.prev = c THEN
  184. c.parent.body := NIL
  185. ELSE
  186. c.prev.next := c.next;
  187. c.next.prev := c.prev
  188. END;
  189. c.parent := NIL
  190. END;
  191. c.prev := NIL; c.next := NIL
  192. END Detach;
  193. PROCEDURE AppendTo*(c: Widget; container: Widget);
  194. VAR r: Widget;
  195. BEGIN
  196. Detach(c);
  197. c.parent := container;
  198. r := container.body;
  199. IF r = NIL THEN
  200. container.body := c;
  201. c.prev := c; c.next := c
  202. ELSE
  203. c.next := r; c.prev := r.prev;
  204. r.prev.next := c; r.prev := c
  205. END
  206. END AppendTo;
  207. PROCEDURE DirectPut*(c, where: Widget; x, y: INTEGER);
  208. BEGIN
  209. IF c # NIL THEN
  210. c.x := x; c.y := y;
  211. IF where # NIL THEN
  212. AppendTo(c, where)
  213. END
  214. END
  215. END DirectPut;
  216. PROCEDURE Put*(c, where: Widget; x, y: INTEGER);
  217. VAR msg: PutMsg;
  218. BEGIN
  219. IF c # NIL THEN
  220. c.x := x; c.y := y;
  221. IF where # NIL THEN
  222. msg.what := c;
  223. msg.x := x;
  224. msg.y := y;
  225. where.handle(where, msg)
  226. END
  227. END
  228. END Put;
  229. PROCEDURE WidgetOnMouseDown*(c: Widget; x, y, btn: INTEGER);
  230. VAR msg: MouseDownMsg;
  231. BEGIN
  232. pressedWidget := c;
  233. Focus(c);
  234. msg.x := x; msg.y := y; msg.btn := btn;
  235. c.handle(c, msg);
  236. IF c.onMouseDown # NIL THEN c.onMouseDown(c, x, y, btn) END
  237. END WidgetOnMouseDown;
  238. PROCEDURE WidgetHandleMouseDown*(c: Widget; x, y, btn: INTEGER);
  239. VAR p: Widget;
  240. BEGIN
  241. p := FindHoveredInRing(c.body, x, y, TRUE);
  242. IF p # NIL THEN
  243. WidgetHandleMouseDown(p, x - p.x, y - p.y, btn)
  244. ELSE
  245. WidgetOnMouseDown(c, x, y, btn)
  246. END
  247. END WidgetHandleMouseDown;
  248. PROCEDURE WidgetOnMouseUp*(c: Widget; x, y, btn: INTEGER);
  249. VAR msg: MouseUpMsg;
  250. BEGIN
  251. pressedWidget := NIL;
  252. msg.x := x; msg.y := y; msg.btn := btn;
  253. c.handle(c, msg);
  254. IF c.onMouseUp # NIL THEN c.onMouseUp(c, x, y, btn) END
  255. END WidgetOnMouseUp;
  256. PROCEDURE WidgetOnClick*(c: Widget);
  257. VAR msg: ClickMsg;
  258. BEGIN c.handle(c, msg);
  259. IF c.onClick # NIL THEN c.onClick(c) END
  260. END WidgetOnClick;
  261. PROCEDURE WidgetHandler*(c: Widget; VAR msg: Message);
  262. VAR x, y: INTEGER;
  263. BEGIN
  264. IF msg IS DrawMsg THEN
  265. x := msg(DrawMsg).x; y := msg(DrawMsg).y;
  266. IF c.onPaint # NIL THEN
  267. c.onPaint(c, x, y, msg(DrawMsg).w, msg(DrawMsg).h)
  268. ELSE
  269. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor);
  270. G.Rect(x, y, x + c.w - 1, y + c.h - 1, c.fgColor);
  271. G.Rect(x + 2, y + 2, x + c.w - 3, y + c.h - 3, c.fgColor)
  272. END
  273. ELSIF msg IS MouseDownMsg THEN
  274. IF msg(MouseDownMsg).btn = 1 THEN c.pressed := TRUE END
  275. ELSIF msg IS MouseUpMsg THEN c.pressed := FALSE
  276. ELSIF msg IS PutMsg THEN
  277. DirectPut(msg(PutMsg).what, c, msg(PutMsg).x, msg(PutMsg).y)
  278. END
  279. END WidgetHandler;
  280. PROCEDURE DrawWidget*(c: Widget; x, y, w, h: INTEGER);
  281. VAR M: DrawMsg;
  282. BEGIN
  283. M.x := x; M.y := y; M.w := w; M.h := h;
  284. c.handle(c, M)
  285. END DrawWidget;
  286. PROCEDURE DrawBody*(c: Widget; x, y, w, h: INTEGER);
  287. VAR p: Widget;
  288. x2, y2, w2, h2: INTEGER;
  289. cx, cy, cw, ch: INTEGER;
  290. CX, CY, CW, CH: INTEGER;
  291. BEGIN
  292. p := c.body;
  293. IF p # NIL THEN
  294. G.GetClip(CX, CY, CW, CH);
  295. IF CX + CW > x + w THEN CW := x + w - CX END;
  296. IF CY + CH > y + h THEN CH := y + h - CY END;
  297. IF CX < x THEN DEC(CW, x - CX); CX := x END;
  298. IF CY < y THEN DEC(CH, y - CY); CY := y END;
  299. REPEAT
  300. x2 := x + p.x; y2 := y + p.y;
  301. w2 := w - p.x; h2 := h - p.y;
  302. cx := x2; cy := y2; cw := p.w; ch := p.h;
  303. IF cx + cw > CX + CW THEN cw := CX + CW - cx END;
  304. IF cy + ch > CY + CH THEN ch := CY + CH - cy END;
  305. IF cx < CX THEN DEC(cw, CX - cx); cx := CX END;
  306. IF cy < CY THEN DEC(ch, CY - cy); cy := CY END;
  307. G.SetClip(cx, cy, cw, ch);
  308. DrawWidget(p, x2, y2, p.w, p.h);
  309. p := p.next
  310. UNTIL p = c.body;
  311. G.UnsetClip
  312. END
  313. END DrawBody;
  314. PROCEDURE SetBgColor*(c: Widget; color: G.Color);
  315. BEGIN c.bgColor := color
  316. END SetBgColor;
  317. PROCEDURE SetFgColor*(c: Widget; color: G.Color);
  318. BEGIN c.fgColor := color
  319. END SetFgColor;
  320. PROCEDURE SetOnPaint*(c: Widget; proc: PROCEDURE (c: Widget; x, y, w, h: INTEGER));
  321. BEGIN c.onPaint := proc
  322. END SetOnPaint;
  323. PROCEDURE SetOnMouseMove*(c: Widget; proc: PROCEDURE (c: Widget; x, y, btn: INTEGER));
  324. BEGIN c.onMouseMove := proc
  325. END SetOnMouseMove;
  326. PROCEDURE SetOnMouseDown*(c: Widget; proc: PROCEDURE (c: Widget; x, y, btn: INTEGER));
  327. BEGIN c.onMouseDown := proc
  328. END SetOnMouseDown;
  329. PROCEDURE SetOnMouseUp*(c: Widget; proc: PROCEDURE (c: Widget; x, y, btn: INTEGER));
  330. BEGIN c.onMouseUp := proc
  331. END SetOnMouseUp;
  332. PROCEDURE SetOnClick*(c: Widget; proc: PROCEDURE (c: Widget));
  333. BEGIN c.onClick := proc
  334. END SetOnClick;
  335. PROCEDURE InitWidget*(c: Widget; w, h: INTEGER);
  336. BEGIN c.x := 0; c.y := 0; c.w := w; c.h := h;
  337. c.focusable := FALSE; c.focused := FALSE;
  338. c.hovered := FALSE; c.pressed := FALSE;
  339. G.MakeCol(c.bgColor, 180, 180, 180);
  340. G.MakeCol(c.fgColor, 0, 0, 0);
  341. c.handle := WidgetHandler
  342. END InitWidget;
  343. (** Creates and returns a new custom widget *)
  344. PROCEDURE NewWidget*(where: Widget; x, y, w, h: INTEGER): Widget;
  345. VAR c: Widget;
  346. BEGIN NEW(c); InitWidget(c, w, h);
  347. Put(c, where, x, y)
  348. RETURN c END NewWidget;
  349. (** Panel **)
  350. PROCEDURE PanelSetNoBg*(c: Panel; noBg: BOOLEAN);
  351. BEGIN c.noBg := noBg
  352. END PanelSetNoBg;
  353. PROCEDURE PanelHandler*(c: Widget; VAR msg: Message);
  354. VAR x, y: INTEGER;
  355. BEGIN
  356. IF msg IS DrawMsg THEN
  357. x := msg(DrawMsg).x; y := msg(DrawMsg).y;
  358. IF ~c(Panel).noBg THEN
  359. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor)
  360. END;
  361. DrawBody(c, x, y, c.w, c.h)
  362. ELSE WidgetHandler(c, msg)
  363. END
  364. END PanelHandler;
  365. PROCEDURE InitPanel*(c: Panel; where: Widget; x, y, w, h: INTEGER);
  366. BEGIN InitWidget(c, w, h);
  367. c.noBg := FALSE;
  368. c.handle := PanelHandler;
  369. Put(c, where, x, y)
  370. END InitPanel;
  371. PROCEDURE NewPanel*(where: Widget; x, y, w, h: INTEGER): Panel;
  372. VAR c: Panel;
  373. BEGIN NEW(c); InitPanel(c, where, x, y, w, h)
  374. RETURN c END NewPanel;
  375. (** App **)
  376. PROCEDURE InitApp*(c: App);
  377. VAR W, H: INTEGER;
  378. BEGIN
  379. G.GetScreenSize(W, H);
  380. InitWidget(c, W, H)
  381. END InitApp;
  382. PROCEDURE NewApp*(): App;
  383. VAR c: App;
  384. BEGIN NEW(c); InitApp(c)
  385. RETURN c END NewApp;
  386. (** Form **)
  387. PROCEDURE DrawForm*(c: Form);
  388. BEGIN
  389. G.FillRect(c.x, c.y, c.x + c.w - 1, c.y + c.h - 1, c.bgColor);
  390. DrawBody(c, c.x, c.y, c.w, c.h)
  391. END DrawForm;
  392. PROCEDURE FormHandler*(c: Widget; VAR msg: Message);
  393. BEGIN WidgetHandler(c, msg)
  394. END FormHandler;
  395. PROCEDURE InitForm*(c: Form; x, y, w, h: INTEGER);
  396. BEGIN InitWidget(c, w, h);
  397. c.x := x; c.y := y;
  398. c.handle := FormHandler;
  399. AppendTo(c, app)
  400. END InitForm;
  401. PROCEDURE NewForm*(x, y, w, h: INTEGER): Form;
  402. VAR c: Form;
  403. BEGIN NEW(c); InitForm(c, x, y, w, h)
  404. RETURN c END NewForm;
  405. (** Button **)
  406. PROCEDURE MakeOrAndYw(bg: G.Color; VAR or, yw: G.Color);
  407. VAR r, g, b: INTEGER;
  408. BEGIN
  409. G.ColorToRGB(bg, r, g, b);
  410. G.MakeCol(yw, (r + 255 * 2) DIV 3, (g + 255 * 3) DIV 4, (b * 3 + 255) DIV 4);
  411. IF (r <= g) & (r <= b) THEN
  412. g := (g * 2 + 255 * 3) DIV 5;
  413. b := (b * 3 + 255) DIV 4
  414. ELSIF (g <= r) & (g <= b) THEN
  415. r := (r * 2 + 255 * 3) DIV 5;
  416. b := (b * 3 + 255) DIV 4
  417. ELSE
  418. r := (r * 2 + 255 * 3) DIV 5;
  419. g := (g * 3 + 255) DIV 4
  420. END;
  421. G.MakeCol(or, r, g, b)
  422. END MakeOrAndYw;
  423. PROCEDURE DrawButtonBox(x, y, w, h: INTEGER; bg, parentBg: G.Color;
  424. down, glow: BOOLEAN);
  425. VAR wh, bl, g1, g2, or, yw: G.Color;
  426. X, Y: INTEGER;
  427. BEGIN
  428. G.MakeCol(bl, 0, 0, 0);
  429. G.MakeCol(wh, 255, 255, 255);
  430. G.MakeCol(g1, 140, 140, 140);
  431. G.MakeCol(g2, 80, 80, 80);
  432. MakeOrAndYw(parentBg, or, yw);
  433. X := x + w - 1; Y := y + h - 1;
  434. G.FillRect(x + 1, y + 1, X - 2, Y - 2, bg);
  435. G.HLine(x + 2, y, X - 1, bl);
  436. G.HLine(x, Y - 1, X - 4, bl);
  437. G.VLine(x, y + 2, Y - 1, bl);
  438. G.VLine(X - 1, y + 1, Y - 4, bl);
  439. IF ~down THEN
  440. G.HLine(x + 3, y + 1, X - 2, wh);
  441. G.HLine(x + 2, Y - 2, X - 4, g1);
  442. G.VLine(x + 1, y + 3, Y - 2, wh);
  443. G.VLine(X - 2, y + 2, Y - 4, g1);
  444. G.PutPixel(X - 3, Y - 3, g1);
  445. G.Line(X - 4, Y - 3, X - 3, Y - 4, g1);
  446. G.PutPixel(x + 2, y + 2, wh)
  447. END;
  448. G.Line(X - 3, Y - 2, X - 2, Y - 3, bl);
  449. G.Line(X - 3, Y - 1, X - 1, Y - 3, g2);
  450. G.Line(x + 1, y + 2, x + 2, y + 1, g1);
  451. G.PutPixel(x + 1, y + 1, bl);
  452. IF glow THEN
  453. G.Line(X - 2, Y - 1, X - 1, Y - 2, yw);
  454. G.HLine(x + 1, Y, X - 2, or);
  455. G.VLine(X, y + 1, Y - 2, or);
  456. G.PutPixel(X - 1, Y - 1, or)
  457. END
  458. END DrawButtonBox;
  459. PROCEDURE DrawButton*(c: Button; x, y, w, h: INTEGER);
  460. VAR fw, fh, tw, tx, ty: INTEGER;
  461. BEGIN
  462. DrawButtonBox(x, y, c.w, c.h, c.bgColor, c.parent.bgColor,
  463. c.pressed & c.hovered, TRUE);
  464. G.GetMonoFontSize(font, fw, fh);
  465. tw := Strings.Length(c.caption) * fw;
  466. tx := x + (c.w - tw) DIV 2;
  467. ty := y + (c.h - fh) DIV 2;
  468. IF c.pressed & c.hovered THEN INC(tx); INC(ty) END;
  469. G.DrawString(c.caption, tx, ty, font, c.fgColor)
  470. END DrawButton;
  471. PROCEDURE ButtonHandler*(c: Widget; VAR msg: Message);
  472. VAR b: Button;
  473. BEGIN b := c(Button);
  474. IF msg IS DrawMsg THEN
  475. DrawButton(b, msg(DrawMsg).x, msg(DrawMsg).y,
  476. msg(DrawMsg).w, msg(DrawMsg).h)
  477. ELSE WidgetHandler(c, msg)
  478. END
  479. END ButtonHandler;
  480. PROCEDURE InitButton*(c: Button; where: Widget;
  481. x, y, w, h: INTEGER; caption: ARRAY OF CHAR);
  482. BEGIN InitWidget(c, w, h);
  483. Strings.Copy(caption, c.caption);
  484. c.focusable := TRUE;
  485. c.handle := ButtonHandler;
  486. Put(c, where, x, y)
  487. END InitButton;
  488. PROCEDURE NewButton*(where: Widget; x, y, w, h: INTEGER; caption: ARRAY OF CHAR): Button;
  489. VAR c: Button;
  490. BEGIN NEW(c); InitButton(c, where, x, y, w, h, caption)
  491. RETURN c END NewButton;
  492. (** Edit **)
  493. PROCEDURE DrawEdit*(c: Edit; x, y, w, h: INTEGER);
  494. VAR fw, fh, tw, tx, ty: INTEGER;
  495. or, yw: G.Color;
  496. BEGIN
  497. MakeOrAndYw(c.parent.bgColor, or, yw);
  498. G.FillRect(x, y, x + c.w - 1, y + c.h - 1, c.bgColor);
  499. G.GetMonoFontSize(font, fw, fh);
  500. tw := Strings.Length(c.text) * fw;
  501. tx := x + 2 - c.off;
  502. ty := y + (c.h - fh) DIV 2;
  503. G.DrawString(c.text, tx, ty, font, c.fgColor);
  504. IF c.focused THEN
  505. INC(tx, fw * c.pos - 1);
  506. G.VLine(tx, ty, ty + fh - 1, or);
  507. G.HLine(tx - 1, ty, tx + 1, or);
  508. G.HLine(tx - 1, ty + fh - 1, tx + 1, or)
  509. END;
  510. G.HLine(x, y, x + c.w - 2, c.fgColor);
  511. G.VLine(x, y, y + c.h - 1, c.fgColor);
  512. G.HLine(x + 1, y + c.h - 1, x + c.w - 1, or);
  513. G.VLine(x + c.w - 1, y, y + c.h - 1, or)
  514. END DrawEdit;
  515. PROCEDURE EditOnMouseDown*(c: Edit; VAR msg: MouseDownMsg);
  516. VAR n, fw, fh: INTEGER;
  517. BEGIN
  518. IF (msg.btn = 1) & (msg.x > 0) & (msg.x < c.w - 1) &
  519. (msg.y > 0) & (msg.y < c.h - 1)
  520. THEN
  521. G.GetMonoFontSize(font, fw, fh);
  522. n := (msg.x - 2 + fw DIV 2) DIV fw;
  523. IF n < 0 THEN n := 0 ELSIF n > c.len THEN n := c.len END;
  524. c.pos := n
  525. END
  526. END EditOnMouseDown;
  527. PROCEDURE EditCheckOffset(c: Edit);
  528. VAR n, fw, fh: INTEGER;
  529. BEGIN
  530. G.GetMonoFontSize(font, fw, fh);
  531. n := c.pos * fw - c.off;
  532. IF c.len * fw <= c.w - 4 THEN c.off := 0
  533. ELSIF n < 0 THEN c.off := c.pos * fw
  534. ELSIF n >= c.w - 4 THEN c.off := c.pos * fw - c.w + 4
  535. ELSIF c.len * fw - c.off <= c.w - 4 THEN c.off := c.len * fw - c.w + 4
  536. END
  537. END EditCheckOffset;
  538. PROCEDURE EditOnChar*(c: Edit; VAR msg: CharMsg);
  539. VAR i: INTEGER;
  540. BEGIN
  541. IF msg.key = G.kBackspace THEN
  542. IF c.pos > 0 THEN
  543. Strings.Delete(c.text, c.pos - 1, 1);
  544. DEC(c.len); DEC(c.pos)
  545. END
  546. ELSIF msg.key = G.kDel THEN
  547. IF c.pos < c.len THEN
  548. Strings.Delete(c.text, c.pos, 1);
  549. DEC(c.len)
  550. END
  551. ELSIF msg.ch < ' ' THEN
  552. IF msg.key = G.kLeft THEN DEC(c.pos)
  553. ELSIF msg.key = G.kRight THEN INC(c.pos)
  554. ELSIF msg.key = G.kHome THEN c.pos := 0
  555. ELSIF msg.key = G.kEnd THEN c.pos := c.len
  556. END;
  557. IF c.pos < 0 THEN c.pos := 0 ELSIF c.pos > c.len THEN c.pos := c.len END
  558. ELSIF c.len < LEN(c.text) - 1 THEN
  559. c.text[c.len + 1] := 0X;
  560. i := c.len;
  561. WHILE i > c.pos DO
  562. c.text[i] := c.text[i - 1];
  563. DEC(i)
  564. END;
  565. c.text[c.pos] := msg.ch;
  566. INC(c.len); INC(c.pos)
  567. END;
  568. EditCheckOffset(c)
  569. END EditOnChar;
  570. PROCEDURE EditHandler*(c: Widget; VAR msg: Message);
  571. VAR e: Edit;
  572. BEGIN e := c(Edit);
  573. IF msg IS DrawMsg THEN
  574. DrawEdit(e, msg(DrawMsg).x, msg(DrawMsg).y,
  575. msg(DrawMsg).w, msg(DrawMsg).h)
  576. ELSIF msg IS MouseDownMsg THEN EditOnMouseDown(e, msg(MouseDownMsg))
  577. ELSIF msg IS CharMsg THEN EditOnChar(e, msg(CharMsg))
  578. ELSE WidgetHandler(c, msg)
  579. END
  580. END EditHandler;
  581. PROCEDURE InitEdit*(c: Edit; where: Widget; x, y, w, h: INTEGER);
  582. BEGIN InitWidget(c, w, h);
  583. c.focusable := TRUE;
  584. G.MakeCol(c.bgColor, 255, 255, 255);
  585. c.text := 'Привет'; c.len := 6; c.pos := 2; c.off := 0;
  586. c.handle := EditHandler;
  587. Put(c, where, x, y)
  588. END InitEdit;
  589. PROCEDURE NewEdit*(where: Widget; x, y, w, h: INTEGER): Edit;
  590. VAR c: Edit;
  591. BEGIN NEW(c); InitEdit(c, where, x, y, w, h)
  592. RETURN c END NewEdit;
  593. PROCEDURE EditSetText*(c: Edit; text: ARRAY OF CHAR);
  594. BEGIN
  595. Strings.Copy(text, c.text);
  596. c.len := Strings.Length(text);
  597. c.pos := 0;
  598. c.off := 0
  599. END EditSetText;
  600. (** ScrollBar **)
  601. PROCEDURE DrawBox(x, y, w, h: INTEGER; bg, fg: G.Color);
  602. BEGIN
  603. G.FillRect(x, y, x + w - 1, y + h - 1, bg);
  604. G.Rect(x, y, x + w - 1, y + h - 1, fg)
  605. END DrawBox;
  606. PROCEDURE DrawHorizScrollBar(c: ScrollBar; x, y, w, h: INTEGER);
  607. VAR fw, fh, X, Y, hs, maxHs, pos, range: INTEGER;
  608. bs: INTEGER; (** Button size *)
  609. grey: G.Color;
  610. BEGIN
  611. G.MakeCol(grey, 80, 80, 80);
  612. DrawButtonBox(x, y, c.w, c.h, c.bgColor, c.parent.bgColor, TRUE, TRUE);
  613. hs := c.handleSize;
  614. bs := c.h;
  615. IF bs > 20 THEN bs := 20 END;
  616. c.btnSize := bs;
  617. maxHs := c.w - bs * 2 + 4;
  618. IF hs > maxHs THEN hs := maxHs END;
  619. range := c.max - c.min;
  620. pos := c.value;
  621. IF pos < c.min THEN pos := c.min ELSIF pos > c.max THEN pos := c.max END;
  622. c.handlePos := bs - 2 + ((maxHs - hs) * pos + range DIV 2) DIV range;
  623. DrawButtonBox(x, y, bs, c.h, c.bgColor,
  624. c.parent.bgColor, c.btnPressed = 1, FALSE);
  625. DrawButtonBox(x + c.w - bs, y, bs, c.h, c.bgColor,
  626. c.parent.bgColor, c.btnPressed = 2, TRUE);
  627. X := x + (bs - 1) DIV 2; Y := y + (bs - 1) DIV 2;
  628. IF c.btnPressed = 1 THEN INC(X); INC(Y) END;
  629. G.HLine(X - 4, Y, X + 4, c.fgColor);
  630. G.Line(X - 4, Y, X - 1, Y + 3, c.fgColor);
  631. G.Line(X - 4, Y, X - 1, Y - 3, c.fgColor);
  632. X := x + c.w - bs DIV 2 - 1;
  633. IF c.btnPressed = 1 THEN DEC(Y) END;
  634. IF c.btnPressed = 2 THEN INC(X); INC(Y) END;
  635. G.HLine(X - 4, Y, X + 4, c.fgColor);
  636. G.Line(X + 4, Y, X + 1, Y + 3, c.fgColor);
  637. G.Line(X + 4, Y, X + 1, Y - 3, c.fgColor);
  638. DrawButtonBox(x + c.handlePos, y, hs, c.h, c.bgColor,
  639. c.parent.bgColor, c.btnPressed = 3, FALSE)
  640. END DrawHorizScrollBar;
  641. PROCEDURE DrawVertScrollBar(c: ScrollBar; x, y, w, h: INTEGER);
  642. VAR fw, fh, X, Y, hs, maxHs, pos, range: INTEGER;
  643. bs: INTEGER; (** Button size *)
  644. grey: G.Color;
  645. BEGIN
  646. G.MakeCol(grey, 80, 80, 80);
  647. DrawButtonBox(x, y, c.w, c.h, c.bgColor, c.parent.bgColor, TRUE, TRUE);
  648. hs := c.handleSize;
  649. bs := c.w;
  650. IF bs > 20 THEN bs := 20 END;
  651. c.btnSize := bs;
  652. maxHs := c.h - bs * 2 + 4;
  653. IF hs > maxHs THEN hs := maxHs END;
  654. range := c.max - c.min;
  655. pos := c.value;
  656. IF pos < c.min THEN pos := c.min ELSIF pos > c.max THEN pos := c.max END;
  657. c.handlePos := bs - 2 + ((maxHs - hs) * pos + range DIV 2) DIV range;
  658. DrawButtonBox(x, y, c.w, bs, c.bgColor,
  659. c.parent.bgColor, c.btnPressed = 1, FALSE);
  660. DrawButtonBox(x, y + c.h - bs, c.w, bs, c.bgColor,
  661. c.parent.bgColor, c.btnPressed = 2, TRUE);
  662. X := x + (bs - 1) DIV 2; Y := y + (bs - 1) DIV 2;
  663. IF c.btnPressed = 1 THEN INC(X); INC(Y) END;
  664. G.VLine(X, Y - 4, Y + 4, c.fgColor);
  665. G.Line(X, Y - 4, X + 3, Y - 1, c.fgColor);
  666. G.Line(X, Y - 4, X - 3, Y - 1, c.fgColor);
  667. Y := y + c.h - bs DIV 2 - 1;
  668. IF c.btnPressed = 1 THEN DEC(X) END;
  669. IF c.btnPressed = 2 THEN INC(X); INC(Y) END;
  670. G.VLine(X, Y - 4, Y + 4, c.fgColor);
  671. G.Line(X, Y + 4, X + 3, Y + 1, c.fgColor);
  672. G.Line(X, Y + 4, X - 3, Y + 1, c.fgColor);
  673. DrawButtonBox(x, y + c.handlePos, c.w, hs, c.bgColor,
  674. c.parent.bgColor, c.btnPressed = 3, FALSE)
  675. END DrawVertScrollBar;
  676. PROCEDURE DrawScrollBar*(c: ScrollBar; x, y, w, h: INTEGER);
  677. BEGIN
  678. IF c.vertical THEN
  679. DrawVertScrollBar(c, x, y, w, h)
  680. ELSE
  681. DrawHorizScrollBar(c, x, y, w, h)
  682. END
  683. END DrawScrollBar;
  684. PROCEDURE ScrollBarSetVertical*(c: ScrollBar; vertical: BOOLEAN);
  685. BEGIN c.vertical := vertical
  686. END ScrollBarSetVertical;
  687. PROCEDURE ScrollBarSetValue*(c: ScrollBar; value: INTEGER);
  688. BEGIN
  689. IF value < c.min THEN value := c.min
  690. ELSIF value > c.max THEN value := c.max
  691. END;
  692. IF c.value # value THEN
  693. c.value := value;
  694. IF c.onScroll # NIL THEN c.onScroll(c, value) END
  695. END
  696. END ScrollBarSetValue;
  697. PROCEDURE HandleScrollBarMouseMove(c: ScrollBar; VAR msg: MouseMoveMsg);
  698. VAR n, x, size, w: INTEGER;
  699. BEGIN
  700. IF c.handlePressed THEN
  701. IF c.vertical THEN x := msg.y; size := c.h
  702. ELSE x := msg.x; size := c.w
  703. END;
  704. w := size - c.btnSize * 2 - c.handleSize;
  705. n := x - c.handlePressPos - c.btnSize;
  706. n := (n * (c.max - c.min) + w DIV 2) DIV w + c.min;
  707. ScrollBarSetValue(c, n)
  708. END
  709. END HandleScrollBarMouseMove;
  710. PROCEDURE HandleScrollBarMouseDown(c: ScrollBar; VAR msg: MouseDownMsg);
  711. VAR x, d, size: INTEGER;
  712. BEGIN
  713. IF c.vertical THEN x := msg.y; size := c.h
  714. ELSE x := msg.x; size := c.w
  715. END;
  716. IF msg.btn = 2 THEN d := 1 ELSE d := c.inc END;
  717. IF x < c.btnSize THEN
  718. c.btnPressed := 1(*Less btn*);
  719. ScrollBarSetValue(c, c.value - d);
  720. ELSIF x >= size - c.btnSize THEN
  721. c.btnPressed := 2(*More btn*);
  722. ScrollBarSetValue(c, c.value + d)
  723. ELSIF msg.btn = 1 THEN
  724. IF (c.handlePos <= x) & (x < c.handlePos + c.handleSize) THEN
  725. c.btnPressed := 3(*Handle*);
  726. c.handlePressed := TRUE;
  727. c.handlePressPos := x - c.handlePos
  728. ELSIF x < c.handlePos THEN
  729. ScrollBarSetValue(c, c.value - c.bigInc)
  730. ELSE
  731. ScrollBarSetValue(c, c.value + c.bigInc)
  732. END
  733. ELSE c.btnPressed := 0(*Nothing*);
  734. END;
  735. WidgetHandler(c, msg)
  736. END HandleScrollBarMouseDown;
  737. PROCEDURE ScrollBarHandler*(c: Widget; VAR msg: Message);
  738. VAR s: ScrollBar;
  739. BEGIN s := c(ScrollBar);
  740. IF msg IS DrawMsg THEN
  741. DrawScrollBar(s, msg(DrawMsg).x, msg(DrawMsg).y,
  742. msg(DrawMsg).w, msg(DrawMsg).h)
  743. ELSIF msg IS MouseMoveMsg THEN HandleScrollBarMouseMove(s, msg(MouseMoveMsg))
  744. ELSIF msg IS MouseDownMsg THEN HandleScrollBarMouseDown(s, msg(MouseDownMsg))
  745. ELSIF msg IS MouseUpMsg THEN s.handlePressed := FALSE; s.btnPressed := 0(*Nothing*)
  746. ELSE WidgetHandler(c, msg)
  747. END
  748. END ScrollBarHandler;
  749. PROCEDURE InitScrollBar*(c: ScrollBar; where: Widget;
  750. x, y, w, h: INTEGER);
  751. BEGIN InitWidget(c, w, h);
  752. c.handle := ScrollBarHandler;
  753. c.value := 0; c.min := 0; c.max := 100; c.inc := 5; c.bigInc := 20;
  754. c.handlePos := 0; c.handleSize := 24; c.btnSize := 0;
  755. c.btnPressed := 0(*Nothing*);
  756. Put(c, where, x, y)
  757. END InitScrollBar;
  758. PROCEDURE NewScrollBar*(where: Widget; x, y, w, h: INTEGER): ScrollBar;
  759. VAR c: ScrollBar;
  760. BEGIN NEW(c); InitScrollBar(c, where, x, y, w, h)
  761. RETURN c END NewScrollBar;
  762. PROCEDURE ScrollBarSetOnScroll*(c: ScrollBar; proc: PROCEDURE (c: ScrollBar; value: INTEGER));
  763. BEGIN c.onScroll := proc
  764. END ScrollBarSetOnScroll;
  765. (** ScrollBox **)
  766. PROCEDURE ScrollBoxSetNoBg*(c: ScrollBox; noBg: BOOLEAN);
  767. BEGIN PanelSetNoBg(c.inner, noBg)
  768. END ScrollBoxSetNoBg;
  769. PROCEDURE ScrollBoxHandler*(c: Widget; VAR msg: Message);
  770. VAR x, y: INTEGER;
  771. BEGIN
  772. IF msg IS DrawMsg THEN
  773. x := msg(DrawMsg).x; y := msg(DrawMsg).y;
  774. DrawBody(c, x, y, c.w, c.h)
  775. ELSIF msg IS PutMsg THEN
  776. DirectPut(msg(PutMsg).what, c(ScrollBox).inner,
  777. msg(PutMsg).x, msg(PutMsg).y)
  778. ELSE WidgetHandler(c, msg)
  779. END
  780. END ScrollBoxHandler;
  781. PROCEDURE ScrollBoxSetInnerSize*(c: ScrollBox; w, h: INTEGER);
  782. BEGIN
  783. Resize(c.inner, w, h);
  784. c.scbHoriz.max := w - c.outer.w;
  785. c.scbVert.max := h - c.outer.h
  786. END ScrollBoxSetInnerSize;
  787. PROCEDURE ScrollBoxOnHorizScroll*(c: ScrollBar; value: INTEGER);
  788. VAR sbx: ScrollBox;
  789. BEGIN
  790. sbx := c.parent(ScrollBox);
  791. sbx.inner.x := -value
  792. END ScrollBoxOnHorizScroll;
  793. PROCEDURE ScrollBoxOnVertScroll*(c: ScrollBar; value: INTEGER);
  794. VAR sbx: ScrollBox;
  795. BEGIN
  796. sbx := c.parent(ScrollBox);
  797. sbx.inner.y := -value
  798. END ScrollBoxOnVertScroll;
  799. PROCEDURE InitScrollBox*(c: ScrollBox; where: Widget; x, y, w, h: INTEGER);
  800. BEGIN InitWidget(c, w, h);
  801. c.handle := ScrollBoxHandler;
  802. c.scbHoriz := NewScrollBar(NIL, 0, 0, w - 16, 16);
  803. DirectPut(c.scbHoriz, c, 0, h - 16);
  804. ScrollBarSetOnScroll(c.scbHoriz, ScrollBoxOnHorizScroll);
  805. c.scbVert := NewScrollBar(NIL, 0, 0, 16, h - 16);
  806. ScrollBarSetVertical(c.scbVert, TRUE);
  807. DirectPut(c.scbVert, c, w - 16, 0);
  808. ScrollBarSetOnScroll(c.scbVert, ScrollBoxOnVertScroll);
  809. c.outer := NewPanel(NIL, 0, 0, w - 16, h - 16);
  810. DirectPut(c.outer, c, 0, 0);
  811. PanelSetNoBg(c.outer, TRUE);
  812. c.inner := NewPanel(c.outer, 0, 0, 1, 1);
  813. ScrollBoxSetInnerSize(c, w * 2, h * 3);
  814. Put(c, where, x, y)
  815. END InitScrollBox;
  816. PROCEDURE NewScrollBox*(where: Widget; x, y, w, h: INTEGER): ScrollBox;
  817. VAR c: ScrollBox;
  818. BEGIN NEW(c); InitScrollBox(c, where, x, y, w, h)
  819. RETURN c END NewScrollBox;
  820. (** General **)
  821. PROCEDURE DrawCursor;
  822. BEGIN
  823. IF mouseX >= 0 THEN
  824. G.Draw(mouseCursor, mouseX, mouseY)
  825. END
  826. END DrawCursor;
  827. PROCEDURE DrawAll;
  828. VAR c: Widget;
  829. BEGIN
  830. G.TargetScreen;
  831. c := app.body;
  832. REPEAT
  833. DrawForm(c(Form));
  834. c := c.next
  835. UNTIL c = app.body;
  836. DrawCursor;
  837. G.Flip
  838. END DrawAll;
  839. PROCEDURE HandleMouseMove(VAR e: G.Event);
  840. VAR c: Widget;
  841. BEGIN
  842. mouseX := e.x; mouseY := e.y;
  843. c := FindHoveredInRing(app.body, e.x, e.y, FALSE);
  844. IF c # NIL THEN
  845. WidgetHandleMouseMove(c, e.x - c.x, e.y - c.y, e.button)
  846. END
  847. END HandleMouseMove;
  848. PROCEDURE HandleMouseDown(VAR e: G.Event);
  849. VAR c: Widget;
  850. BEGIN
  851. pressedX := 0; pressedY := 0;
  852. c := FindHoveredInRing(app.body, e.x, e.y, TRUE);
  853. IF c # NIL THEN
  854. WidgetHandleMouseDown(c, e.x - c.x, e.y - c.y, e.button)
  855. END
  856. END HandleMouseDown;
  857. PROCEDURE HandleMouseUp(VAR e: G.Event);
  858. VAR c: Widget;
  859. BEGIN
  860. IF pressedWidget # NIL THEN
  861. c := pressedWidget;
  862. IF ~c.hovered THEN c := NIL END;
  863. WidgetOnMouseUp(pressedWidget, e.x - pressedX, e.y - pressedY, e.button);
  864. IF (c # NIL) & (e.button = 1) THEN
  865. WidgetOnClick(c)
  866. END
  867. END
  868. END HandleMouseUp;
  869. PROCEDURE HandleKeyDown(VAR e: G.Event);
  870. VAR msg: KeyDownMsg;
  871. BEGIN
  872. IF focusedWidget # NIL THEN
  873. msg.key := e.key;
  874. focusedWidget.handle(focusedWidget, msg)
  875. END
  876. END HandleKeyDown;
  877. PROCEDURE HandleKeyUp(VAR e: G.Event);
  878. VAR msg: KeyUpMsg;
  879. BEGIN
  880. IF focusedWidget # NIL THEN
  881. msg.key := e.key;
  882. focusedWidget.handle(focusedWidget, msg)
  883. END
  884. END HandleKeyUp;
  885. PROCEDURE HandleChar(VAR e: G.Event);
  886. VAR msg: CharMsg;
  887. BEGIN
  888. IF focusedWidget # NIL THEN
  889. msg.key := e.key; msg.ch := e.ch;
  890. msg.mod := e.mod; msg.repeat := e.repeat;
  891. focusedWidget.handle(focusedWidget, msg)
  892. END
  893. END HandleChar;
  894. PROCEDURE HandleEvent(VAR e: G.Event);
  895. BEGIN
  896. IF e.type = G.quit THEN quit := TRUE
  897. ELSIF e.type = G.mouseMove THEN HandleMouseMove(e)
  898. ELSIF e.type = G.mouseDown THEN HandleMouseDown(e)
  899. ELSIF e.type = G.mouseUp THEN HandleMouseUp(e)
  900. ELSIF e.type = G.keyDown THEN HandleKeyDown(e)
  901. ELSIF e.type = G.keyUp THEN HandleKeyUp(e)
  902. ELSIF e.type = G.char THEN HandleChar(e)
  903. END
  904. END HandleEvent;
  905. PROCEDURE Quit*;
  906. BEGIN quit := TRUE
  907. END Quit;
  908. PROCEDURE Run*;
  909. VAR e: G.Event;
  910. BEGIN
  911. quit := FALSE;
  912. REPEAT
  913. WHILE ~quit & G.HasEvents() DO
  914. G.WaitEvent(e);
  915. HandleEvent(e)
  916. END;
  917. DrawAll
  918. UNTIL quit
  919. END Run;
  920. PROCEDURE CreateArrowCursor(): G.Bitmap;
  921. VAR m: G.Bitmap;
  922. bl, wh: G.Color;
  923. i: INTEGER;
  924. BEGIN
  925. m := G.NewBitmap(10, 16);
  926. G.ClearBitmap(m);
  927. G.Target(m);
  928. G.MakeCol(bl, 0, 0, 0);
  929. G.MakeCol(wh, 255, 255, 255);
  930. G.PutPixel(1, 1, wh);
  931. FOR i := 2 TO 8 DO G.HLine(1, i, i, wh) END;
  932. G.HLine(1, 9, 5, wh);
  933. G.HLine(1, 10, 5, wh);
  934. G.PutPixel(1, 11, wh);
  935. G.HLine(5, 11, 6, wh);
  936. G.HLine(5, 12, 6, wh);
  937. G.HLine(6, 13, 7, wh);
  938. G.HLine(6, 14, 7, wh);
  939. G.Line(1, 0, 9, 8, bl);
  940. G.VLine(0, 1, 12, bl);
  941. G.Line(1, 12, 3, 10, bl);
  942. G.Line(4, 11, 5, 14, bl);
  943. G.HLine(6, 15, 7, bl);
  944. G.Line(6, 9, 8, 14, bl);
  945. G.HLine(7, 9, 9, bl);
  946. RETURN m END CreateArrowCursor;
  947. PROCEDURE InitCursor;
  948. BEGIN
  949. mouseCursor := CreateArrowCursor();
  950. mouseX := -1; mouseY := 0;
  951. G.ShowMouse(FALSE)
  952. END InitCursor;
  953. PROCEDURE Init*;
  954. BEGIN
  955. font := G.LoadFont('Data/Fonts/Main');
  956. IF font = NIL THEN Out.String('SimpleGui: could not load font.'); Out.Ln END;
  957. InitCursor;
  958. Done := font # NIL;
  959. app := NewApp();
  960. hoveredWidget := NIL; pressedWidget := NIL;
  961. pressedX := 0; pressedY := 0
  962. END Init;
  963. END SimpleGui.