m2gtkdemo.mod 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. MODULE m2gtkdemo ;
  2. (*
  3. m2-GTK4 - an m2 gtk-demo.
  4. A browser window with a searchable sidebar of demos; activating a row
  5. (double-click / Enter) or pressing "Run" opens the demo in its own
  6. window, mirroring the GTK demo application.
  7. Build: make demos
  8. Run: ./build/demos/m2gtkdemo
  9. *)
  10. FROM Gio IMPORT g_application_run;
  11. FROM GtkApplication IMPORT gtk_application_new;
  12. FROM GtkApplicationWindow IMPORT gtk_application_window_new;
  13. FROM GtkWindow IMPORT gtk_window_set_title, gtk_window_set_default_size,
  14. gtk_window_set_child, gtk_window_present;
  15. FROM GtkBox IMPORT gtk_box_new, gtk_box_append, gtk_box_set_spacing;
  16. FROM GtkEnums IMPORT GtkVertical, GtkHorizontal;
  17. FROM GtkWidget IMPORT gtk_widget_set_size_request, gtk_widget_set_vexpand,
  18. gtk_widget_set_hexpand, gtk_widget_set_margin_start,
  19. gtk_widget_set_margin_end, gtk_widget_set_margin_top,
  20. gtk_widget_set_margin_bottom;
  21. FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_text;
  22. FROM GtkButton IMPORT gtk_button_new_with_label;
  23. FROM GtkSearchEntry IMPORT gtk_search_entry_new,
  24. gtk_search_entry_set_placeholder_text;
  25. FROM GtkEditable IMPORT gtk_editable_get_text;
  26. FROM GtkListView IMPORT gtk_list_view_new;
  27. FROM GtkListItem IMPORT gtk_list_item_get_item, gtk_list_item_get_child,
  28. gtk_list_item_set_child;
  29. FROM GtkSignalListItemFactory IMPORT gtk_signal_list_item_factory_new;
  30. FROM GtkSingleSelection IMPORT gtk_single_selection_new,
  31. gtk_single_selection_get_selected;
  32. FROM GtkFilterListModel IMPORT gtk_filter_list_model_new;
  33. FROM GtkCustomFilter IMPORT gtk_custom_filter_new,
  34. gtk_custom_filter_set_filter_func;
  35. FROM GtkStringList IMPORT gtk_string_list_new, gtk_string_list_append;
  36. FROM GtkStringObject IMPORT gtk_string_object_get_string;
  37. FROM GListModel IMPORT g_list_model_get_item;
  38. FROM GObject IMPORT g_signal_connect_data, g_object_unref, GConnectDefault;
  39. FROM GtkClosures IMPORT Connect2, Connect3;
  40. FROM GtkUtils IMPORT Connect, CStrToM2;
  41. FROM GtkDemo IMPORT Count, TitleOf, BuildByTitle;
  42. FROM SYSTEM IMPORT ADDRESS, ADR;
  43. FROM libc IMPORT printf;
  44. CONST
  45. AppId = "org.example.m2gtk4.Demo4";
  46. Invalid = 0FFFFFFFFH;
  47. VAR
  48. window, filter, filterModel, selection: ADDRESS;
  49. searchText: ARRAY [0..63] OF CHAR;
  50. PROCEDURE Contains (hay, needle: ARRAY OF CHAR) : BOOLEAN;
  51. VAR
  52. i, j, hl, nl: CARDINAL;
  53. found: BOOLEAN;
  54. BEGIN
  55. hl := 0;
  56. WHILE (hl <= HIGH(hay)) AND (hay[hl] # 0C) DO INC(hl) END;
  57. nl := 0;
  58. WHILE (nl <= HIGH(needle)) AND (needle[nl] # 0C) DO INC(nl) END;
  59. IF nl = 0 THEN RETURN TRUE END;
  60. IF nl > hl THEN RETURN FALSE END;
  61. i := 0;
  62. WHILE i + nl <= hl DO
  63. found := TRUE;
  64. j := 0;
  65. WHILE j < nl DO
  66. IF hay[i + j] # needle[j] THEN found := FALSE END;
  67. INC(j)
  68. END;
  69. IF found THEN RETURN TRUE END;
  70. INC(i)
  71. END;
  72. RETURN FALSE
  73. END Contains;
  74. (* gboolean match(gpointer item, gpointer user_data) - match the title *)
  75. PROCEDURE Match (item: ADDRESS; user: ADDRESS) : INTEGER;
  76. VAR
  77. buf: ARRAY [0..63] OF CHAR;
  78. BEGIN
  79. CStrToM2(gtk_string_object_get_string(item), buf);
  80. IF Contains(buf, searchText) THEN RETURN 1 ELSE RETURN 0 END
  81. END Match;
  82. PROCEDURE OnSearchChanged (entry: ADDRESS; user: ADDRESS);
  83. BEGIN
  84. CStrToM2(gtk_editable_get_text(entry), searchText);
  85. gtk_custom_filter_set_filter_func(filter, ADR(Match), NIL, NIL)
  86. END OnSearchChanged;
  87. PROCEDURE RunPosition (position: CARDINAL);
  88. VAR
  89. item, demoWindow: ADDRESS;
  90. title: ARRAY [0..63] OF CHAR;
  91. BEGIN
  92. item := g_list_model_get_item(filterModel, position);
  93. CStrToM2(gtk_string_object_get_string(item), title);
  94. g_object_unref(item);
  95. demoWindow := BuildByTitle(title, window);
  96. IF demoWindow = NIL THEN
  97. printf("no demo named %s\n", title)
  98. END
  99. END RunPosition;
  100. (* void activate(GtkListView *list, guint position, gpointer user) *)
  101. PROCEDURE OnActivate (list: ADDRESS; position: CARDINAL; user: ADDRESS);
  102. BEGIN
  103. RunPosition(position)
  104. END OnActivate;
  105. PROCEDURE OnRun (button: ADDRESS; user: ADDRESS);
  106. VAR
  107. index: CARDINAL;
  108. BEGIN
  109. index := gtk_single_selection_get_selected(selection);
  110. IF index # Invalid THEN RunPosition(index) END
  111. END OnRun;
  112. PROCEDURE RowSetup (factory: ADDRESS; item: ADDRESS; user: ADDRESS);
  113. BEGIN
  114. gtk_list_item_set_child(item, gtk_label_new(""))
  115. END RowSetup;
  116. PROCEDURE RowBind (factory: ADDRESS; item: ADDRESS; user: ADDRESS);
  117. VAR
  118. obj, child: ADDRESS;
  119. buf: ARRAY [0..63] OF CHAR;
  120. BEGIN
  121. obj := gtk_list_item_get_item(item);
  122. CStrToM2(gtk_string_object_get_string(obj), buf);
  123. child := gtk_list_item_get_child(item);
  124. gtk_label_set_text(child, buf)
  125. END RowBind;
  126. PROCEDURE OnActivateApp (application: ADDRESS; data: ADDRESS);
  127. VAR
  128. root, content, search, listView, factory, store, runButton, hint: ADDRESS;
  129. title: ARRAY [0..63] OF CHAR;
  130. i: CARDINAL;
  131. BEGIN
  132. searchText[0] := 0C;
  133. store := gtk_string_list_new(NIL);
  134. i := 0;
  135. WHILE i < Count() DO
  136. TitleOf(i, title);
  137. gtk_string_list_append(store, title);
  138. INC(i)
  139. END;
  140. filter := gtk_custom_filter_new(ADR(Match), NIL, NIL);
  141. filterModel := gtk_filter_list_model_new(store, filter);
  142. selection := gtk_single_selection_new(filterModel);
  143. factory := gtk_signal_list_item_factory_new();
  144. Connect3(factory, "setup", RowSetup, NIL);
  145. Connect3(factory, "bind", RowBind, NIL);
  146. listView := gtk_list_view_new(selection, factory);
  147. gtk_widget_set_size_request(listView, 200, -1);
  148. gtk_widget_set_vexpand(listView, 1);
  149. g_signal_connect_data(listView, "activate", ADR(OnActivate), NIL, NIL,
  150. GConnectDefault);
  151. runButton := gtk_button_new_with_label("Run selected demo");
  152. Connect2(runButton, "clicked", OnRun, NIL);
  153. hint := gtk_label_new("Pick a demo, then Run (or double-click).");
  154. gtk_widget_set_margin_start(hint, 8);
  155. search := gtk_search_entry_new();
  156. gtk_search_entry_set_placeholder_text(search, "Search demos");
  157. Connect2(search, "search-changed", OnSearchChanged, NIL);
  158. content := gtk_box_new(GtkHorizontal, 8);
  159. gtk_box_set_spacing(content, 8);
  160. gtk_widget_set_vexpand(content, 1);
  161. gtk_box_append(content, listView);
  162. gtk_box_append(content, runButton);
  163. gtk_widget_set_hexpand(runButton, 0);
  164. root := gtk_box_new(GtkVertical, 8);
  165. gtk_box_set_spacing(root, 8);
  166. gtk_widget_set_margin_start(root, 10);
  167. gtk_widget_set_margin_end(root, 10);
  168. gtk_widget_set_margin_top(root, 10);
  169. gtk_widget_set_margin_bottom(root, 10);
  170. gtk_box_append(root, search);
  171. gtk_box_append(root, content);
  172. gtk_box_append(root, hint);
  173. window := gtk_application_window_new(application);
  174. gtk_window_set_title(window, "m2-GTK4 Demo");
  175. gtk_window_set_default_size(window, 480, 360);
  176. gtk_window_set_child(window, root);
  177. gtk_window_present(window)
  178. END OnActivateApp;
  179. VAR
  180. app: ADDRESS;
  181. BEGIN
  182. app := gtk_application_new(AppId, 0);
  183. IF app = NIL THEN
  184. printf("gtk_application_new failed\n");
  185. HALT(1)
  186. END;
  187. Connect2(app, "activate", OnActivateApp, NIL);
  188. g_application_run(app, 0, NIL)
  189. END m2gtkdemo.