DemosWindows.mod 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. IMPLEMENTATION MODULE DemosWindows ;
  2. (*
  3. m2-GTK4 - window-oriented gtk-demo ports, following the gtk-demo
  4. pattern used by DemosBasic/DemoImpl: each Do* procedure creates its
  5. window once (module VAR), then toggles visibility - showing it, or
  6. destroying it and resetting the handle to NIL - and returns it.
  7. Originals: gtk/demos/gtk-demo/{headerbar,infobar,tabs,assistant}.c
  8. Simplifications forced by the curated bindings under src/:
  9. * GtkInfoBar is not bound, so DoInfoBar lays the messages out as
  10. plain labels plus toggle buttons instead of real info bars.
  11. * Pango tab arrays and gtk_text_view_set_tabs() are not bound, so
  12. DoTabs omits the tab-stop setup (the sample text is unchanged).
  13. * GtkAccessible and g_object_bind_property are not bound; the
  14. accessibility annotations and the toggle/info-bar bindings are
  15. dropped.
  16. * gtk_widget_set_display() / g_object_add_weak_pointer() are not
  17. used, matching the existing demos (display is inherited, and the
  18. module VAR is reset to NIL explicitly).
  19. *)
  20. FROM SYSTEM IMPORT ADDRESS;
  21. FROM GtkWindow IMPORT gtk_window_new, gtk_window_set_title,
  22. gtk_window_set_default_size, gtk_window_set_resizable,
  23. gtk_window_set_child, gtk_window_destroy, gtk_window_set_titlebar;
  24. FROM GtkWidget IMPORT gtk_widget_set_visible, gtk_widget_get_visible,
  25. gtk_widget_set_margin_start, gtk_widget_set_margin_end,
  26. gtk_widget_set_margin_top, gtk_widget_set_margin_bottom,
  27. gtk_widget_set_halign, gtk_widget_set_valign, gtk_widget_set_hexpand,
  28. gtk_widget_add_css_class;
  29. FROM GtkEnums IMPORT GtkHorizontal, GtkVertical, GtkAlignCenter,
  30. GtkAlignFill, GtkWrapWord;
  31. FROM GtkHeaderBar IMPORT gtk_header_bar_new, gtk_header_bar_pack_start,
  32. gtk_header_bar_pack_end;
  33. FROM GtkBox IMPORT gtk_box_new, gtk_box_append;
  34. FROM GtkImage IMPORT gtk_image_new_from_icon_name;
  35. FROM GtkButton IMPORT gtk_button_new, gtk_button_set_child;
  36. FROM GtkSwitch IMPORT gtk_switch_new;
  37. FROM GtkTextView IMPORT gtk_text_view_new, gtk_text_view_get_buffer,
  38. gtk_text_view_set_wrap_mode, gtk_text_view_set_top_margin,
  39. gtk_text_view_set_bottom_margin, gtk_text_view_set_left_margin,
  40. gtk_text_view_set_right_margin;
  41. FROM GtkTextBuffer IMPORT gtk_text_buffer_set_text;
  42. FROM GtkScrolledWindow IMPORT gtk_scrolled_window_new,
  43. gtk_scrolled_window_set_child, gtk_scrolled_window_set_policy,
  44. GtkPolicyNever, GtkPolicyAutomatic;
  45. FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_wrap;
  46. FROM GtkToggleButton IMPORT gtk_toggle_button_new_with_label;
  47. FROM GtkFrame IMPORT gtk_frame_new, gtk_frame_set_child;
  48. FROM GtkAssistant IMPORT gtk_assistant_new, gtk_assistant_append_page,
  49. gtk_assistant_set_page_title, gtk_assistant_set_page_type,
  50. gtk_assistant_set_page_complete, gtk_assistant_get_current_page,
  51. gtk_assistant_get_n_pages, gtk_assistant_get_nth_page,
  52. gtk_assistant_commit, AssistantPageIntro, AssistantPageConfirm,
  53. AssistantPageProgress;
  54. FROM GtkEntry IMPORT gtk_entry_new, gtk_entry_set_activates_default;
  55. FROM GtkEditable IMPORT gtk_editable_get_text;
  56. FROM GtkCheckButton IMPORT gtk_check_button_new_with_label;
  57. FROM GtkProgressBar IMPORT gtk_progress_bar_new,
  58. gtk_progress_bar_get_fraction, gtk_progress_bar_set_fraction;
  59. FROM GtkClosures IMPORT Connect2, Connect3;
  60. FROM GtkUtils IMPORT StrAppend, IntToStr, CStrToM2;
  61. FROM GLib IMPORT g_timeout_add, GSourceContinue, GSourceRemove;
  62. (* ------------------------------------------------------------------ *)
  63. (* Header Bar (headerbar.c) *)
  64. (* ------------------------------------------------------------------ *)
  65. VAR
  66. headerBarWindow: ADDRESS;
  67. (* gtk_button_new_from_icon_name() is not bound: build the equivalent
  68. from an empty button and an icon-name GtkImage child. *)
  69. PROCEDURE IconButton (name: ARRAY OF CHAR) : ADDRESS;
  70. VAR
  71. button: ADDRESS;
  72. BEGIN
  73. button := gtk_button_new();
  74. gtk_button_set_child(button, gtk_image_new_from_icon_name(name));
  75. RETURN button
  76. END IconButton;
  77. PROCEDURE DoHeaderBar (doWidget: ADDRESS) : ADDRESS;
  78. VAR
  79. header, button, box, content: ADDRESS;
  80. BEGIN
  81. IF headerBarWindow = NIL THEN
  82. headerBarWindow := gtk_window_new();
  83. gtk_window_set_title(headerBarWindow, "Welcome to the Hotel California");
  84. gtk_window_set_default_size(headerBarWindow, 600, 400);
  85. header := gtk_header_bar_new();
  86. button := IconButton("mail-send-receive-symbolic");
  87. gtk_header_bar_pack_end(header, button);
  88. box := gtk_box_new(GtkHorizontal, 0);
  89. gtk_widget_add_css_class(box, "linked");
  90. button := IconButton("go-previous-symbolic");
  91. gtk_box_append(box, button);
  92. button := IconButton("go-next-symbolic");
  93. gtk_box_append(box, button);
  94. gtk_header_bar_pack_start(header, box);
  95. button := gtk_switch_new();
  96. gtk_header_bar_pack_start(header, button);
  97. gtk_window_set_titlebar(headerBarWindow, header);
  98. content := gtk_text_view_new();
  99. gtk_window_set_child(headerBarWindow, content)
  100. END;
  101. IF gtk_widget_get_visible(headerBarWindow) = 0 THEN
  102. gtk_widget_set_visible(headerBarWindow, 1)
  103. ELSE
  104. gtk_window_destroy(headerBarWindow);
  105. headerBarWindow := NIL
  106. END;
  107. RETURN headerBarWindow
  108. END DoHeaderBar;
  109. (* ------------------------------------------------------------------ *)
  110. (* Info Bars (infobar.c) *)
  111. (* ------------------------------------------------------------------ *)
  112. VAR
  113. infoBarWindow: ADDRESS;
  114. (* GtkInfoBar is not bound by m2-GTK4, so this simplified port shows the
  115. five message types as wrapped labels, with a linked row of toggle
  116. buttons underneath, all inside a titled frame. *)
  117. PROCEDURE DoInfoBar (doWidget: ADDRESS) : ADDRESS;
  118. VAR
  119. vbox, frame, actions, label, button: ADDRESS;
  120. BEGIN
  121. IF infoBarWindow = NIL THEN
  122. actions := gtk_box_new(GtkHorizontal, 0);
  123. gtk_widget_add_css_class(actions, "linked");
  124. infoBarWindow := gtk_window_new();
  125. gtk_window_set_title(infoBarWindow, "Info Bars");
  126. gtk_window_set_resizable(infoBarWindow, 0);
  127. vbox := gtk_box_new(GtkVertical, 0);
  128. gtk_widget_set_margin_start(vbox, 8);
  129. gtk_widget_set_margin_end(vbox, 8);
  130. gtk_widget_set_margin_top(vbox, 8);
  131. gtk_widget_set_margin_bottom(vbox, 8);
  132. gtk_window_set_child(infoBarWindow, vbox);
  133. label := gtk_label_new("This is an info bar with message type GTK_MESSAGE_INFO");
  134. gtk_label_set_wrap(label, 1);
  135. gtk_box_append(vbox, label);
  136. button := gtk_toggle_button_new_with_label("Message");
  137. gtk_box_append(actions, button);
  138. label := gtk_label_new("This is an info bar with message type GTK_MESSAGE_WARNING");
  139. gtk_label_set_wrap(label, 1);
  140. gtk_box_append(vbox, label);
  141. button := gtk_toggle_button_new_with_label("Warning");
  142. gtk_box_append(actions, button);
  143. label := gtk_label_new("This is an info bar with message type GTK_MESSAGE_QUESTION");
  144. gtk_label_set_wrap(label, 1);
  145. gtk_box_append(vbox, label);
  146. button := gtk_toggle_button_new_with_label("Question");
  147. gtk_box_append(actions, button);
  148. label := gtk_label_new("This is an info bar with message type GTK_MESSAGE_ERROR");
  149. gtk_label_set_wrap(label, 1);
  150. gtk_box_append(vbox, label);
  151. button := gtk_toggle_button_new_with_label("Error");
  152. gtk_box_append(actions, button);
  153. label := gtk_label_new("This is an info bar with message type GTK_MESSAGE_OTHER");
  154. gtk_label_set_wrap(label, 1);
  155. gtk_box_append(vbox, label);
  156. button := gtk_toggle_button_new_with_label("Other");
  157. gtk_box_append(actions, button);
  158. frame := gtk_frame_new("An example of different info bars");
  159. gtk_widget_set_margin_top(frame, 8);
  160. gtk_widget_set_margin_bottom(frame, 8);
  161. gtk_box_append(vbox, frame);
  162. gtk_widget_set_halign(actions, GtkAlignCenter);
  163. gtk_widget_set_margin_start(actions, 8);
  164. gtk_widget_set_margin_end(actions, 8);
  165. gtk_widget_set_margin_top(actions, 8);
  166. gtk_widget_set_margin_bottom(actions, 8);
  167. gtk_frame_set_child(frame, actions)
  168. END;
  169. IF gtk_widget_get_visible(infoBarWindow) = 0 THEN
  170. gtk_widget_set_visible(infoBarWindow, 1)
  171. ELSE
  172. gtk_window_destroy(infoBarWindow);
  173. infoBarWindow := NIL
  174. END;
  175. RETURN infoBarWindow
  176. END DoInfoBar;
  177. (* ------------------------------------------------------------------ *)
  178. (* Text View/Tabs (tabs.c) *)
  179. (* ------------------------------------------------------------------ *)
  180. VAR
  181. tabsWindow: ADDRESS;
  182. (* Pango tab arrays and gtk_text_view_set_tabs() are not bound; the tab
  183. stops are therefore omitted, but the sample text is preserved (built
  184. with explicit TAB/LF characters so no escape sequences are needed). *)
  185. PROCEDURE SetTabsText (buffer: ADDRESS);
  186. VAR
  187. text: ARRAY [0..127] OF CHAR;
  188. tab, nl: ARRAY [0..1] OF CHAR;
  189. BEGIN
  190. tab[0] := CHR(9);
  191. tab[1] := 0C;
  192. nl[0] := CHR(10);
  193. nl[1] := 0C;
  194. text[0] := 0C;
  195. StrAppend(text, "one"); StrAppend(text, tab);
  196. StrAppend(text, "2.0"); StrAppend(text, tab);
  197. StrAppend(text, "three"); StrAppend(text, nl);
  198. StrAppend(text, "four"); StrAppend(text, tab);
  199. StrAppend(text, "5.555"); StrAppend(text, tab);
  200. StrAppend(text, "six"); StrAppend(text, nl);
  201. StrAppend(text, "seven"); StrAppend(text, tab);
  202. StrAppend(text, "88.88"); StrAppend(text, tab);
  203. StrAppend(text, "nine");
  204. gtk_text_buffer_set_text(buffer, text, -1)
  205. END SetTabsText;
  206. PROCEDURE DoTabs (doWidget: ADDRESS) : ADDRESS;
  207. VAR
  208. view, sw, buffer: ADDRESS;
  209. BEGIN
  210. IF tabsWindow = NIL THEN
  211. tabsWindow := gtk_window_new();
  212. gtk_window_set_title(tabsWindow, "Tabs");
  213. gtk_window_set_default_size(tabsWindow, 330, 130);
  214. gtk_window_set_resizable(tabsWindow, 0);
  215. view := gtk_text_view_new();
  216. gtk_text_view_set_wrap_mode(view, GtkWrapWord);
  217. gtk_text_view_set_top_margin(view, 20);
  218. gtk_text_view_set_bottom_margin(view, 20);
  219. gtk_text_view_set_left_margin(view, 20);
  220. gtk_text_view_set_right_margin(view, 20);
  221. buffer := gtk_text_view_get_buffer(view);
  222. SetTabsText(buffer);
  223. sw := gtk_scrolled_window_new();
  224. gtk_scrolled_window_set_policy(sw, GtkPolicyNever, GtkPolicyAutomatic);
  225. gtk_window_set_child(tabsWindow, sw);
  226. gtk_scrolled_window_set_child(sw, view)
  227. END;
  228. IF gtk_widget_get_visible(tabsWindow) = 0 THEN
  229. gtk_widget_set_visible(tabsWindow, 1)
  230. ELSE
  231. gtk_window_destroy(tabsWindow);
  232. tabsWindow := NIL
  233. END;
  234. RETURN tabsWindow
  235. END DoTabs;
  236. (* ------------------------------------------------------------------ *)
  237. (* Assistant (assistant.c) *)
  238. (* ------------------------------------------------------------------ *)
  239. VAR
  240. assistantWindow, progressBar: ADDRESS;
  241. (* gboolean apply_changes_gradually(gpointer data) *)
  242. PROCEDURE ApplyChangesGradually (data: ADDRESS) : INTEGER;
  243. VAR
  244. fraction: REAL;
  245. BEGIN
  246. fraction := gtk_progress_bar_get_fraction(progressBar);
  247. fraction := fraction + 0.05;
  248. IF fraction < 1.0 THEN
  249. gtk_progress_bar_set_fraction(progressBar, fraction);
  250. RETURN GSourceContinue
  251. ELSE
  252. gtk_window_destroy(data);
  253. RETURN GSourceRemove
  254. END
  255. END ApplyChangesGradually;
  256. (* void on_assistant_apply(GtkWidget *widget, gpointer data) *)
  257. PROCEDURE OnAssistantApply (widget: ADDRESS; data: ADDRESS);
  258. BEGIN
  259. g_timeout_add(100, ApplyChangesGradually, widget)
  260. END OnAssistantApply;
  261. (* void on_assistant_close_cancel(GtkWidget *widget, gpointer data) *)
  262. PROCEDURE OnAssistantCloseCancel (widget: ADDRESS; data: ADDRESS);
  263. BEGIN
  264. gtk_window_destroy(widget)
  265. END OnAssistantCloseCancel;
  266. (* gint format "Sample assistant (%d of %d)" without g_strdup_printf. *)
  267. PROCEDURE MakeAssistantTitle (current, total: INTEGER;
  268. VAR title: ARRAY OF CHAR);
  269. VAR
  270. num: ARRAY [0..15] OF CHAR;
  271. BEGIN
  272. title[0] := 0C;
  273. StrAppend(title, "Sample assistant (");
  274. IntToStr(current, num);
  275. StrAppend(title, num);
  276. StrAppend(title, " of ");
  277. IntToStr(total, num);
  278. StrAppend(title, num);
  279. StrAppend(title, ")")
  280. END MakeAssistantTitle;
  281. (* void on_assistant_prepare(GtkWidget *widget, GtkWidget *page, gpointer data) *)
  282. PROCEDURE OnAssistantPrepare (widget: ADDRESS; page: ADDRESS; data: ADDRESS);
  283. VAR
  284. currentPage, nPages: INTEGER;
  285. title: ARRAY [0..63] OF CHAR;
  286. BEGIN
  287. currentPage := gtk_assistant_get_current_page(widget);
  288. nPages := gtk_assistant_get_n_pages(widget);
  289. MakeAssistantTitle(currentPage + 1, nPages, title);
  290. gtk_window_set_title(widget, title);
  291. (* The fourth page (zero-based) is the progress page: commit once the
  292. user has clicked Apply to reach it. *)
  293. IF currentPage = 3 THEN
  294. gtk_assistant_commit(widget)
  295. END
  296. END OnAssistantPrepare;
  297. (* void on_entry_changed(GtkWidget *widget, gpointer data) *)
  298. PROCEDURE OnEntryChanged (widget: ADDRESS; data: ADDRESS);
  299. VAR
  300. currentPage: ADDRESS;
  301. pageNumber: INTEGER;
  302. text: ARRAY [0..1] OF CHAR;
  303. BEGIN
  304. pageNumber := gtk_assistant_get_current_page(data);
  305. currentPage := gtk_assistant_get_nth_page(data, pageNumber);
  306. CStrToM2(gtk_editable_get_text(widget), text);
  307. IF text[0] # 0C THEN
  308. gtk_assistant_set_page_complete(data, currentPage, 1)
  309. ELSE
  310. gtk_assistant_set_page_complete(data, currentPage, 0)
  311. END
  312. END OnEntryChanged;
  313. PROCEDURE CreatePage1 (assistant: ADDRESS);
  314. VAR
  315. box, label, entry: ADDRESS;
  316. BEGIN
  317. box := gtk_box_new(GtkHorizontal, 12);
  318. gtk_widget_set_margin_start(box, 12);
  319. gtk_widget_set_margin_end(box, 12);
  320. gtk_widget_set_margin_top(box, 12);
  321. gtk_widget_set_margin_bottom(box, 12);
  322. label := gtk_label_new("You must fill out this entry to continue:");
  323. gtk_box_append(box, label);
  324. entry := gtk_entry_new();
  325. gtk_entry_set_activates_default(entry, 1);
  326. gtk_widget_set_valign(entry, GtkAlignCenter);
  327. gtk_box_append(box, entry);
  328. Connect2(entry, "changed", OnEntryChanged, assistant);
  329. gtk_assistant_append_page(assistant, box);
  330. gtk_assistant_set_page_title(assistant, box, "Page 1");
  331. gtk_assistant_set_page_type(assistant, box, AssistantPageIntro)
  332. END CreatePage1;
  333. PROCEDURE CreatePage2 (assistant: ADDRESS);
  334. VAR
  335. box, checkbutton: ADDRESS;
  336. BEGIN
  337. box := gtk_box_new(GtkHorizontal, 12);
  338. gtk_widget_set_margin_start(box, 12);
  339. gtk_widget_set_margin_end(box, 12);
  340. gtk_widget_set_margin_top(box, 12);
  341. gtk_widget_set_margin_bottom(box, 12);
  342. checkbutton := gtk_check_button_new_with_label
  343. ("This is optional data, you may continue even if you do not check this");
  344. gtk_widget_set_valign(checkbutton, GtkAlignCenter);
  345. gtk_box_append(box, checkbutton);
  346. gtk_assistant_append_page(assistant, box);
  347. gtk_assistant_set_page_complete(assistant, box, 1);
  348. gtk_assistant_set_page_title(assistant, box, "Page 2")
  349. END CreatePage2;
  350. PROCEDURE CreatePage3 (assistant: ADDRESS);
  351. VAR
  352. label: ADDRESS;
  353. BEGIN
  354. label := gtk_label_new("This is a confirmation page, press 'Apply' to apply changes");
  355. gtk_assistant_append_page(assistant, label);
  356. gtk_assistant_set_page_type(assistant, label, AssistantPageConfirm);
  357. gtk_assistant_set_page_complete(assistant, label, 1);
  358. gtk_assistant_set_page_title(assistant, label, "Confirmation")
  359. END CreatePage3;
  360. PROCEDURE CreatePage4 (assistant: ADDRESS);
  361. BEGIN
  362. progressBar := gtk_progress_bar_new();
  363. gtk_widget_set_halign(progressBar, GtkAlignFill);
  364. gtk_widget_set_valign(progressBar, GtkAlignCenter);
  365. gtk_widget_set_hexpand(progressBar, 1);
  366. gtk_widget_set_margin_start(progressBar, 40);
  367. gtk_widget_set_margin_end(progressBar, 40);
  368. gtk_assistant_append_page(assistant, progressBar);
  369. gtk_assistant_set_page_type(assistant, progressBar, AssistantPageProgress);
  370. gtk_assistant_set_page_title(assistant, progressBar, "Applying changes");
  371. (* Prevents the assistant from being closed while we are "busy". *)
  372. gtk_assistant_set_page_complete(assistant, progressBar, 0)
  373. END CreatePage4;
  374. PROCEDURE DoAssistant (doWidget: ADDRESS) : ADDRESS;
  375. BEGIN
  376. IF assistantWindow = NIL THEN
  377. assistantWindow := gtk_assistant_new();
  378. gtk_window_set_default_size(assistantWindow, -1, 300);
  379. CreatePage1(assistantWindow);
  380. CreatePage2(assistantWindow);
  381. CreatePage3(assistantWindow);
  382. CreatePage4(assistantWindow);
  383. Connect2(assistantWindow, "cancel", OnAssistantCloseCancel, NIL);
  384. Connect2(assistantWindow, "close", OnAssistantCloseCancel, NIL);
  385. Connect2(assistantWindow, "apply", OnAssistantApply, NIL);
  386. Connect3(assistantWindow, "prepare", OnAssistantPrepare, NIL)
  387. END;
  388. IF gtk_widget_get_visible(assistantWindow) = 0 THEN
  389. gtk_widget_set_visible(assistantWindow, 1)
  390. ELSE
  391. gtk_window_destroy(assistantWindow);
  392. assistantWindow := NIL
  393. END;
  394. RETURN assistantWindow
  395. END DoAssistant;
  396. END DemosWindows.