SimpleGui.Mod 29 KB

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