2
0

SimpleGui.Mod 35 KB

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