DemoImpl.mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. IMPLEMENTATION MODULE DemoImpl ;
  2. (*
  3. Five demos ported from the GTK source tree (gtk/demos/gtk-demo),
  4. simplified to the features bound by m2-GTK4:
  5. Links (links.c) - markup with hyperlinks + activate-link
  6. List Box (listbox.c) - rows in a GtkListBox
  7. Flow Box (flowbox.c) - reflowing color swatches
  8. Expander (expander.c) - collapsible scrolled text
  9. CSS Basics (css_basics.c) - live CSS editing
  10. *)
  11. FROM SYSTEM IMPORT ADDRESS, ADR;
  12. FROM GtkWindow IMPORT gtk_window_new, gtk_window_set_title,
  13. gtk_window_set_default_size, gtk_window_set_resizable,
  14. gtk_window_set_child, gtk_window_destroy;
  15. FROM GtkWidget IMPORT gtk_widget_set_visible, gtk_widget_get_visible,
  16. gtk_widget_set_margin_start, gtk_widget_set_margin_end,
  17. gtk_widget_set_margin_top, gtk_widget_set_margin_bottom,
  18. gtk_widget_set_vexpand, gtk_widget_add_css_class;
  19. FROM GtkEnums IMPORT GtkVertical, GtkSelectionNone;
  20. FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_use_markup,
  21. gtk_label_set_wrap, gtk_label_set_wrap_mode, gtk_label_set_max_width_chars;
  22. FROM GtkBox IMPORT gtk_box_new, gtk_box_append, gtk_box_set_spacing;
  23. FROM GtkScrolledWindow IMPORT gtk_scrolled_window_new,
  24. gtk_scrolled_window_set_child, gtk_scrolled_window_set_min_content_height,
  25. gtk_scrolled_window_set_has_frame;
  26. FROM GtkListBox IMPORT gtk_list_box_new, gtk_list_box_append,
  27. gtk_list_box_row_new, gtk_list_box_row_set_child;
  28. FROM GtkFlowBox IMPORT gtk_flow_box_new, gtk_flow_box_append,
  29. gtk_flow_box_set_selection_mode, gtk_flow_box_set_max_children_per_line;
  30. FROM GtkDrawingArea IMPORT gtk_drawing_area_new,
  31. gtk_drawing_area_set_content_width, gtk_drawing_area_set_content_height,
  32. gtk_drawing_area_set_draw_func;
  33. FROM GtkButton IMPORT gtk_button_new, gtk_button_set_child;
  34. FROM GtkExpander IMPORT gtk_expander_new, gtk_expander_set_child;
  35. FROM GtkTextView IMPORT gtk_text_view_new, gtk_text_view_new_with_buffer;
  36. FROM GtkTextBuffer IMPORT gtk_text_buffer_new, gtk_text_buffer_set_text,
  37. gtk_text_buffer_get_text, gtk_text_buffer_get_start_iter,
  38. gtk_text_buffer_get_end_iter;
  39. FROM GtkTextIter IMPORT GtkTextIter;
  40. FROM GtkCssProvider IMPORT gtk_css_provider_new,
  41. gtk_css_provider_load_from_string;
  42. FROM GtkStyleContext IMPORT gtk_style_context_add_provider_for_display,
  43. GtkStyleProviderPriorityApplication;
  44. FROM GtkAlertDialog IMPORT gtk_alert_dialog_new, gtk_alert_dialog_set_detail,
  45. gtk_alert_dialog_show;
  46. FROM Gdk IMPORT gdk_display_get_default, GdkRGBA, gdk_rgba_parse,
  47. gdk_cairo_set_source_rgba;
  48. FROM Cairo IMPORT cairo_paint;
  49. FROM GObject IMPORT g_signal_connect_data, g_object_unref, GConnectDefault;
  50. FROM GtkClosures IMPORT Connect2;
  51. FROM GtkUtils IMPORT IntToStr, Free, CStrToM2;
  52. FROM GLib IMPORT g_strcmp0;
  53. FROM libc IMPORT printf;
  54. (* ------------------------------------------------------------------ *)
  55. (* Links *)
  56. (* ------------------------------------------------------------------ *)
  57. VAR
  58. linksWindow: ADDRESS;
  59. CONST
  60. LinksMarkup = "Some <a href='http://en.wikipedia.org/wiki/Text' title='plain text'>text</a> may be marked up as hyperlinks, which can be clicked or activated via <a href='keynav'>keynav</a>, working fine alongside other markup such as <a href='http://www.flathub.org/'><b>Flathub</b></a>.";
  61. (* gboolean activate_link(GtkWidget *label, const char *uri, gpointer data) *)
  62. PROCEDURE OnActivateLink (label: ADDRESS; uri: ADDRESS; data: ADDRESS) : INTEGER;
  63. VAR
  64. dialog: ADDRESS;
  65. key: ARRAY [0..7] OF CHAR;
  66. BEGIN
  67. key := "keynav";
  68. IF g_strcmp0(uri, ADR(key)) = 0 THEN
  69. dialog := gtk_alert_dialog_new("Keyboard navigation");
  70. gtk_alert_dialog_set_detail(dialog,
  71. "keynav is a shorthand for keyboard navigation.");
  72. gtk_alert_dialog_show(dialog, NIL);
  73. g_object_unref(dialog);
  74. RETURN 1
  75. END;
  76. RETURN 0
  77. END OnActivateLink;
  78. PROCEDURE DoLinks (doWidget: ADDRESS) : ADDRESS;
  79. VAR
  80. label: ADDRESS;
  81. BEGIN
  82. IF linksWindow = NIL THEN
  83. linksWindow := gtk_window_new();
  84. gtk_window_set_title(linksWindow, "Links");
  85. gtk_window_set_resizable(linksWindow, 0);
  86. label := gtk_label_new(LinksMarkup);
  87. gtk_label_set_use_markup(label, 1);
  88. gtk_label_set_max_width_chars(label, 40);
  89. gtk_label_set_wrap(label, 1);
  90. gtk_label_set_wrap_mode(label, 0); (* PANGO_WRAP_WORD *)
  91. g_signal_connect_data(label, "activate-link", ADR(OnActivateLink),
  92. NIL, NIL, GConnectDefault);
  93. gtk_widget_set_margin_start(label, 20);
  94. gtk_widget_set_margin_end(label, 20);
  95. gtk_widget_set_margin_top(label, 20);
  96. gtk_widget_set_margin_bottom(label, 20);
  97. gtk_window_set_child(linksWindow, label)
  98. END;
  99. IF gtk_widget_get_visible(linksWindow) = 0 THEN
  100. gtk_widget_set_visible(linksWindow, 1)
  101. ELSE
  102. gtk_window_destroy(linksWindow);
  103. linksWindow := NIL
  104. END;
  105. RETURN linksWindow
  106. END DoLinks;
  107. (* ------------------------------------------------------------------ *)
  108. (* List Box *)
  109. (* ------------------------------------------------------------------ *)
  110. VAR
  111. listBoxWindow: ADDRESS;
  112. PROCEDURE DoListBox (doWidget: ADDRESS) : ADDRESS;
  113. VAR
  114. box, row, sw: ADDRESS;
  115. i: INTEGER;
  116. text: ARRAY [0..15] OF CHAR;
  117. BEGIN
  118. IF listBoxWindow = NIL THEN
  119. listBoxWindow := gtk_window_new();
  120. gtk_window_set_title(listBoxWindow, "List Box");
  121. gtk_window_set_default_size(listBoxWindow, 260, 220);
  122. box := gtk_list_box_new();
  123. FOR i := 1 TO 5 DO
  124. row := gtk_list_box_row_new();
  125. IntToStr(i, text);
  126. gtk_list_box_row_set_child(row, gtk_label_new(text));
  127. gtk_list_box_append(box, row)
  128. END;
  129. sw := gtk_scrolled_window_new();
  130. gtk_scrolled_window_set_child(sw, box);
  131. gtk_window_set_child(listBoxWindow, sw)
  132. END;
  133. IF gtk_widget_get_visible(listBoxWindow) = 0 THEN
  134. gtk_widget_set_visible(listBoxWindow, 1)
  135. ELSE
  136. gtk_window_destroy(listBoxWindow);
  137. listBoxWindow := NIL
  138. END;
  139. RETURN listBoxWindow
  140. END DoListBox;
  141. (* ------------------------------------------------------------------ *)
  142. (* Flow Box *)
  143. (* ------------------------------------------------------------------ *)
  144. VAR
  145. flowBoxWindow: ADDRESS;
  146. colors: ARRAY [0..11] OF ARRAY [0..31] OF CHAR;
  147. (* void draw_color(GtkDrawingArea *area, cairo_t *cr, int w, int h, gpointer d) *)
  148. PROCEDURE DrawColor (area: ADDRESS; cr: ADDRESS; width, height: INTEGER;
  149. data: ADDRESS);
  150. VAR
  151. spec: ARRAY [0..31] OF CHAR;
  152. rgba: GdkRGBA;
  153. BEGIN
  154. CStrToM2(data, spec);
  155. IF gdk_rgba_parse(rgba, spec) # 0 THEN
  156. gdk_cairo_set_source_rgba(cr, rgba);
  157. cairo_paint(cr)
  158. END
  159. END DrawColor;
  160. PROCEDURE ColorSwatch (color: ADDRESS) : ADDRESS;
  161. VAR
  162. button, area: ADDRESS;
  163. BEGIN
  164. button := gtk_button_new();
  165. area := gtk_drawing_area_new();
  166. gtk_drawing_area_set_content_width(area, 24);
  167. gtk_drawing_area_set_content_height(area, 24);
  168. gtk_drawing_area_set_draw_func(area, ADR(DrawColor), color, NIL);
  169. gtk_button_set_child(button, area);
  170. RETURN button
  171. END ColorSwatch;
  172. PROCEDURE DoFlowBox (doWidget: ADDRESS) : ADDRESS;
  173. VAR
  174. sw, flowbox: ADDRESS;
  175. i: INTEGER;
  176. BEGIN
  177. IF flowBoxWindow = NIL THEN
  178. flowBoxWindow := gtk_window_new();
  179. gtk_window_set_title(flowBoxWindow, "Flow Box");
  180. gtk_window_set_default_size(flowBoxWindow, 320, 260);
  181. colors[0] := "AliceBlue"; colors[1] := "AntiqueWhite";
  182. colors[2] := "aqua"; colors[3] := "blue";
  183. colors[4] := "chartreuse"; colors[5] := "coral";
  184. colors[6] := "crimson"; colors[7] := "DarkOrange";
  185. colors[8] := "gold"; colors[9] := "ForestGreen";
  186. colors[10] := "Orchid"; colors[11] := "SteelBlue";
  187. flowbox := gtk_flow_box_new();
  188. gtk_flow_box_set_selection_mode(flowbox, GtkSelectionNone);
  189. gtk_flow_box_set_max_children_per_line(flowbox, 8);
  190. FOR i := 0 TO 11 DO
  191. gtk_flow_box_append(flowbox, ColorSwatch(ADR(colors[i])))
  192. END;
  193. sw := gtk_scrolled_window_new();
  194. gtk_scrolled_window_set_child(sw, flowbox);
  195. gtk_window_set_child(flowBoxWindow, sw)
  196. END;
  197. IF gtk_widget_get_visible(flowBoxWindow) = 0 THEN
  198. gtk_widget_set_visible(flowBoxWindow, 1)
  199. ELSE
  200. gtk_window_destroy(flowBoxWindow);
  201. flowBoxWindow := NIL
  202. END;
  203. RETURN flowBoxWindow
  204. END DoFlowBox;
  205. (* ------------------------------------------------------------------ *)
  206. (* Expander *)
  207. (* ------------------------------------------------------------------ *)
  208. VAR
  209. expanderWindow: ADDRESS;
  210. PROCEDURE DoExpander (doWidget: ADDRESS) : ADDRESS;
  211. VAR
  212. box, expander, sw, tv: ADDRESS;
  213. BEGIN
  214. IF expanderWindow = NIL THEN
  215. expanderWindow := gtk_window_new();
  216. gtk_window_set_title(expanderWindow, "Expander");
  217. gtk_window_set_default_size(expanderWindow, 320, 260);
  218. box := gtk_box_new(GtkVertical, 10);
  219. gtk_box_set_spacing(box, 10);
  220. gtk_widget_set_margin_start(box, 10);
  221. gtk_widget_set_margin_end(box, 10);
  222. gtk_widget_set_margin_top(box, 10);
  223. gtk_widget_set_margin_bottom(box, 10);
  224. gtk_box_append(box, gtk_label_new("Here are some more details:"));
  225. expander := gtk_expander_new("Details:");
  226. gtk_widget_set_vexpand(expander, 1);
  227. tv := gtk_text_view_new();
  228. sw := gtk_scrolled_window_new();
  229. gtk_scrolled_window_set_min_content_height(sw, 100);
  230. gtk_scrolled_window_set_has_frame(sw, 1);
  231. gtk_scrolled_window_set_child(sw, tv);
  232. gtk_widget_set_vexpand(sw, 1);
  233. gtk_expander_set_child(expander, sw);
  234. gtk_box_append(box, expander);
  235. gtk_window_set_child(expanderWindow, box)
  236. END;
  237. IF gtk_widget_get_visible(expanderWindow) = 0 THEN
  238. gtk_widget_set_visible(expanderWindow, 1)
  239. ELSE
  240. gtk_window_destroy(expanderWindow);
  241. expanderWindow := NIL
  242. END;
  243. RETURN expanderWindow
  244. END DoExpander;
  245. (* ------------------------------------------------------------------ *)
  246. (* CSS Basics *)
  247. (* ------------------------------------------------------------------ *)
  248. VAR
  249. cssWindow, cssBuffer, cssProvider: ADDRESS;
  250. CONST
  251. InitialCss = ".sample { color: #1c71d8; font-weight: bold; font-size: 20px; }";
  252. PROCEDURE ApplyCss;
  253. VAR
  254. start, stop: GtkTextIter;
  255. text: ADDRESS;
  256. buf: ARRAY [0..1023] OF CHAR;
  257. BEGIN
  258. gtk_text_buffer_get_start_iter(cssBuffer, start);
  259. gtk_text_buffer_get_end_iter(cssBuffer, stop);
  260. text := gtk_text_buffer_get_text(cssBuffer, start, stop, 0);
  261. IF text # NIL THEN
  262. CStrToM2(text, buf);
  263. gtk_css_provider_load_from_string(cssProvider, buf);
  264. Free(text)
  265. END
  266. END ApplyCss;
  267. PROCEDURE OnCssChanged (buffer: ADDRESS; user: ADDRESS);
  268. BEGIN
  269. ApplyCss
  270. END OnCssChanged;
  271. PROCEDURE DoCss (doWidget: ADDRESS) : ADDRESS;
  272. VAR
  273. box, view, sw, sample: ADDRESS;
  274. BEGIN
  275. IF cssWindow = NIL THEN
  276. cssWindow := gtk_window_new();
  277. gtk_window_set_title(cssWindow, "CSS Basics");
  278. gtk_window_set_default_size(cssWindow, 400, 300);
  279. cssProvider := gtk_css_provider_new();
  280. gtk_style_context_add_provider_for_display(gdk_display_get_default(),
  281. cssProvider, GtkStyleProviderPriorityApplication);
  282. sample := gtk_label_new("Sample label (styled by the CSS below)");
  283. gtk_widget_add_css_class(sample, "sample");
  284. cssBuffer := gtk_text_buffer_new(NIL);
  285. gtk_text_buffer_set_text(cssBuffer, InitialCss, -1);
  286. view := gtk_text_view_new_with_buffer(cssBuffer);
  287. sw := gtk_scrolled_window_new();
  288. gtk_scrolled_window_set_child(sw, view);
  289. gtk_scrolled_window_set_min_content_height(sw, 120);
  290. gtk_widget_set_vexpand(sw, 1);
  291. box := gtk_box_new(GtkVertical, 10);
  292. gtk_box_set_spacing(box, 10);
  293. gtk_widget_set_margin_start(box, 10);
  294. gtk_widget_set_margin_end(box, 10);
  295. gtk_widget_set_margin_top(box, 10);
  296. gtk_widget_set_margin_bottom(box, 10);
  297. gtk_box_append(box, sample);
  298. gtk_box_append(box, sw);
  299. Connect2(cssBuffer, "changed", OnCssChanged, NIL);
  300. gtk_window_set_child(cssWindow, box);
  301. ApplyCss
  302. END;
  303. IF gtk_widget_get_visible(cssWindow) = 0 THEN
  304. gtk_widget_set_visible(cssWindow, 1)
  305. ELSE
  306. gtk_window_destroy(cssWindow);
  307. cssWindow := NIL
  308. END;
  309. RETURN cssWindow
  310. END DoCss;
  311. END DemoImpl.