microui-headless.mod 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. MODULE microuiHeadless;
  2. (* Off-screen smoke test for the Modula-2 microui port: builds a representative
  3. UI, renders it with tigr into a bitmap and writes microui-demo.png.
  4. Build (from this directory), after tigr.o, helper.o, microuiHelpers.o and
  5. microui.o have been built in modula2/:
  6. gm2 -fiso -I ../../ ../../tigr.o ../../helper.o \
  7. ../../microuiHelpers.o ../../microui.o \
  8. microui-headless.mod -o microui-headless -lGL -lX11
  9. *)
  10. FROM SYSTEM IMPORT ADDRESS, ADR, CAST, ADDADR, BYTE;
  11. FROM tigr IMPORT TigrPtr, tigrBitmap, tigrClear, tigrPrint, tigrSaveImage,
  12. tigrFree, tigrFillRect, tigrRect, tigrTextWidth, tigrTextHeight,
  13. tfont, TPixelType;
  14. FROM microuiHelpers IMPORT BITAND;
  15. FROM helper IMPORT tigrRGB;
  16. IMPORT microui;
  17. FROM InOut IMPORT WriteString, WriteLn;
  18. TYPE
  19. CharArrayPtr = POINTER TO ARRAY [0..0] OF CHAR;
  20. TextCommandPtr = POINTER TO microui.TextCommand;
  21. RectCommandPtr = POINTER TO microui.RectCommand;
  22. CONST
  23. WIN_W = 760;
  24. WIN_H = 520;
  25. VAR
  26. ctx : microui.Context;
  27. ctxPtr : microui.ContextPtr;
  28. bmp : TigrPtr;
  29. ok : INTEGER;
  30. PROCEDURE MinI(a, b : INTEGER) : INTEGER;
  31. BEGIN IF a < b THEN RETURN a ELSE RETURN b END END MinI;
  32. PROCEDURE MaxI(a, b : INTEGER) : INTEGER;
  33. BEGIN IF a > b THEN RETURN a ELSE RETURN b END END MaxI;
  34. PROCEDURE Pix(c : microui.Color) : TPixelType;
  35. VAR p : TPixelType;
  36. BEGIN
  37. p.r := c.r; p.g := c.g; p.b := c.b; p.a := c.a;
  38. RETURN p
  39. END Pix;
  40. PROCEDURE TextWidthCB(VAR a : microui.TextWidthArgs) : INTEGER;
  41. VAR src : CharArrayPtr;
  42. tmp : ARRAY [0..511] OF CHAR;
  43. n, i : INTEGER;
  44. BEGIN
  45. src := CAST(CharArrayPtr, a.str);
  46. IF a.len < 0 THEN
  47. n := 0;
  48. WHILE (src^[n] # 0C) AND (n < 511) DO
  49. tmp[n] := src^[n];
  50. n := n + 1
  51. END
  52. ELSE
  53. n := a.len;
  54. IF n > 511 THEN n := 511 END;
  55. FOR i := 0 TO n - 1 DO tmp[i] := src^[i] END
  56. END;
  57. tmp[n] := 0C;
  58. RETURN tigrTextWidth(tfont, tmp)
  59. END TextWidthCB;
  60. PROCEDURE TextHeightCB(VAR a : microui.TextHeightArgs) : INTEGER;
  61. BEGIN
  62. RETURN tigrTextHeight(tfont, "")
  63. END TextHeightCB;
  64. PROCEDURE FillRectI(x, y, w, h : INTEGER; c : microui.Color);
  65. VAR x0, y0, x1, y1 : INTEGER;
  66. BEGIN
  67. x0 := MaxI(x, 0);
  68. y0 := MaxI(y, 0);
  69. x1 := MinI(x + w, WIN_W);
  70. y1 := MinI(y + h, WIN_H);
  71. IF (x1 > x0) AND (y1 > y0) THEN
  72. (* tigrFillRect only fills the interior; pair it with tigrRect so the
  73. whole rect (including 1px borders) is drawn, with clipping/blending *)
  74. tigrRect(bmp, VAL(CARDINAL, x0), VAL(CARDINAL, y0),
  75. VAL(CARDINAL, x1 - x0), VAL(CARDINAL, y1 - y0), Pix(c));
  76. tigrFillRect(bmp, VAL(CARDINAL, x0), VAL(CARDINAL, y0),
  77. VAL(CARDINAL, x1 - x0), VAL(CARDINAL, y1 - y0), Pix(c))
  78. END
  79. END FillRectI;
  80. PROCEDURE BuildUI;
  81. VAR widths : ARRAY [0..3] OF INTEGER;
  82. inputBuf : ARRAY [0..63] OF CHAR;
  83. checks : ARRAY [0..1] OF INTEGER;
  84. dummy : INTEGER;
  85. cptr : microui.IntPtr;
  86. bgv : SHORTREAL;
  87. BEGIN
  88. inputBuf := "Hello, microui!";
  89. checks[0] := 1; checks[1] := 0;
  90. bgv := 120.0;
  91. IF microui.beginWindow(ctxPtr, "Demo Window",
  92. microui.rect(30, 30, 330, 440)) # 0 THEN
  93. IF microui.headerEx(ctxPtr, "Window Info", microui.OPT_EXPANDED) # 0 THEN
  94. widths[0] := 64; widths[1] := -1;
  95. microui.layoutRow(ctxPtr, 2, ADR(widths), 0);
  96. microui.label(ctxPtr, "Position:");
  97. microui.label(ctxPtr, "30, 30");
  98. microui.label(ctxPtr, "Size:");
  99. microui.label(ctxPtr, "330, 440")
  100. END;
  101. IF microui.headerEx(ctxPtr, "Widgets", microui.OPT_EXPANDED) # 0 THEN
  102. widths[0] := 100; widths[1] := -1;
  103. microui.layoutRow(ctxPtr, 2, ADR(widths), 0);
  104. microui.label(ctxPtr, "Button:");
  105. dummy := microui.button(ctxPtr, "Press me");
  106. microui.label(ctxPtr, "Slider:");
  107. dummy := microui.slider(ctxPtr, CAST(microui.RealPtr, ADR(bgv)),
  108. 0.0, 255.0);
  109. microui.label(ctxPtr, "Checkbox:");
  110. cptr := CAST(microui.IntPtr, ADR(checks[0]));
  111. dummy := microui.checkbox(ctxPtr, "Enabled", cptr);
  112. microui.label(ctxPtr, "Text box:");
  113. dummy := microui.textbox(ctxPtr, ADR(inputBuf), SIZE(inputBuf))
  114. END;
  115. IF microui.headerEx(ctxPtr, "Tree", microui.OPT_EXPANDED) # 0 THEN
  116. IF microui.beginTreenode(ctxPtr, "Node A") # 0 THEN
  117. microui.label(ctxPtr, "child one");
  118. microui.label(ctxPtr, "child two");
  119. microui.endTreenode(ctxPtr)
  120. END;
  121. IF microui.beginTreenode(ctxPtr, "Node B") # 0 THEN
  122. dummy := microui.button(ctxPtr, "Inside B");
  123. microui.endTreenode(ctxPtr)
  124. END
  125. END;
  126. IF microui.headerEx(ctxPtr, "Text", microui.OPT_EXPANDED) # 0 THEN
  127. widths[0] := -1;
  128. microui.layoutRow(ctxPtr, 1, ADR(widths), 0);
  129. microui.text(ctxPtr, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas lacinia, sem eu lacinia molestie.");
  130. microui.layoutRow(ctxPtr, 1, ADR(widths), 0);
  131. microui.text(ctxPtr, "The quick brown fox jumps over the lazy dog.")
  132. END;
  133. microui.endWindow(ctxPtr)
  134. END;
  135. IF microui.beginWindow(ctxPtr, "Second Window",
  136. microui.rect(380, 30, 340, 160)) # 0 THEN
  137. widths[0] := -1;
  138. microui.layoutRow(ctxPtr, 1, ADR(widths), 0);
  139. microui.text(ctxPtr, "A second window to check z-ordering and colours.");
  140. widths[0] := -1; widths[1] := 120;
  141. microui.layoutRow(ctxPtr, 2, ADR(widths), 0);
  142. microui.label(ctxPtr, "Disabled:");
  143. dummy := microui.buttonEx(ctxPtr, "Nope", 0, microui.OPT_NOINTERACT);
  144. microui.endWindow(ctxPtr)
  145. END
  146. END BuildUI;
  147. PROCEDURE Render;
  148. VAR cmd : microui.CommandPtr;
  149. tcp : TextCommandPtr;
  150. rcp : RectCommandPtr;
  151. src : CharArrayPtr;
  152. x, y : INTEGER;
  153. BEGIN
  154. tigrClear(bmp, tigrRGB(90, 95, 100));
  155. cmd := NIL;
  156. WHILE microui.nextCommand(ctxPtr, cmd) # 0 DO
  157. IF cmd^.type = microui.COMMAND_RECT THEN
  158. rcp := CAST(RectCommandPtr, cmd);
  159. FillRectI(rcp^.rect.x, rcp^.rect.y, rcp^.rect.w, rcp^.rect.h,
  160. rcp^.color)
  161. ELSIF cmd^.type = microui.COMMAND_TEXT THEN
  162. tcp := CAST(TextCommandPtr, cmd);
  163. src := CAST(CharArrayPtr,
  164. ADDADR(CAST(ADDRESS, tcp), SIZE(microui.TextCommand)));
  165. x := MaxI(tcp^.pos.x, 0);
  166. y := MaxI(tcp^.pos.y, 0);
  167. tigrPrint(bmp, tfont, VAL(CARDINAL, x), VAL(CARDINAL, y),
  168. Pix(tcp^.color), src^)
  169. END
  170. END
  171. END Render;
  172. BEGIN
  173. bmp := tigrBitmap(WIN_W, WIN_H);
  174. ctxPtr := CAST(microui.ContextPtr, ADR(ctx));
  175. microui.init(ctxPtr);
  176. ctxPtr^.textWidth := TextWidthCB;
  177. ctxPtr^.textHeight := TextHeightCB;
  178. ctxPtr^.style^.font := CAST(ADDRESS, tfont);
  179. (* Run a few frames with synthetic input so hover/focus/drag paths are
  180. exercised before the final frame is saved. *)
  181. microui.inputMousemove(ctxPtr, 120, 100);
  182. microui.begin(ctxPtr);
  183. BuildUI;
  184. microui.end(ctxPtr);
  185. microui.inputMousedown(ctxPtr, 120, 100, microui.MOUSE_LEFT);
  186. microui.begin(ctxPtr);
  187. BuildUI;
  188. microui.end(ctxPtr);
  189. microui.inputMousemove(ctxPtr, 160, 130);
  190. microui.begin(ctxPtr);
  191. BuildUI;
  192. microui.end(ctxPtr);
  193. microui.inputMouseup(ctxPtr, 160, 130, microui.MOUSE_LEFT);
  194. microui.inputMousemove(ctxPtr, 60, 60);
  195. microui.begin(ctxPtr);
  196. BuildUI;
  197. microui.end(ctxPtr);
  198. Render;
  199. ok := tigrSaveImage("microui-demo.png", bmp);
  200. IF ok = 0 THEN
  201. WriteString("tigrSaveImage failed");
  202. WriteLn
  203. ELSE
  204. WriteString("wrote microui-demo.png");
  205. WriteLn
  206. END;
  207. tigrFree(bmp)
  208. END microuiHeadless.