| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- MODULE m2gtkdemo ;
- (*
- m2-GTK4 - an m2 gtk-demo.
- A browser in the spirit of GTK's own gtk4-demo: a searchable sidebar
- listing every demo in DemoCatalog, and an info pane describing the
- selected demo. Activating a demo (double-click / Enter) or pressing
- "Run" opens it in its own window; demos that have not been ported yet
- are shown as such.
- Build: make demos
- Run: ./build/demos/m2gtkdemo
- *)
- FROM Gio IMPORT g_application_run;
- FROM GtkApplication IMPORT gtk_application_new;
- FROM GtkApplicationWindow IMPORT gtk_application_window_new;
- FROM GtkWindow IMPORT gtk_window_set_title, gtk_window_set_default_size,
- gtk_window_set_child, gtk_window_present;
- FROM GtkBox IMPORT gtk_box_new, gtk_box_append, gtk_box_set_spacing;
- FROM GtkPaned IMPORT gtk_paned_new, gtk_paned_set_start_child,
- gtk_paned_set_end_child, gtk_paned_set_position;
- FROM GtkEnums IMPORT GtkVertical, GtkHorizontal;
- FROM GtkWidget IMPORT gtk_widget_set_size_request, gtk_widget_set_vexpand,
- gtk_widget_set_hexpand, gtk_widget_set_margin_start,
- gtk_widget_set_margin_end, gtk_widget_set_margin_top,
- gtk_widget_set_margin_bottom;
- FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_text,
- gtk_label_set_wrap, gtk_label_set_max_width_chars;
- FROM GtkButton IMPORT gtk_button_new_with_label;
- FROM GtkSearchEntry IMPORT gtk_search_entry_new,
- gtk_search_entry_set_placeholder_text;
- FROM GtkEditable IMPORT gtk_editable_get_text;
- FROM GtkScrolledWindow IMPORT gtk_scrolled_window_new,
- gtk_scrolled_window_set_child;
- FROM GtkListView IMPORT gtk_list_view_new;
- FROM GtkListItem IMPORT gtk_list_item_get_item, gtk_list_item_get_child,
- gtk_list_item_set_child;
- FROM GtkSignalListItemFactory IMPORT gtk_signal_list_item_factory_new;
- FROM GtkSingleSelection IMPORT gtk_single_selection_new,
- gtk_single_selection_get_selected;
- FROM GtkFilterListModel IMPORT gtk_filter_list_model_new;
- FROM GtkCustomFilter IMPORT gtk_custom_filter_new,
- gtk_custom_filter_set_filter_func;
- FROM GtkStringList IMPORT gtk_string_list_new, gtk_string_list_append;
- FROM GtkStringObject IMPORT gtk_string_object_get_string;
- FROM GListModel IMPORT g_list_model_get_item;
- FROM GObject IMPORT g_signal_connect_data, g_object_unref, GConnectDefault;
- FROM GtkClosures IMPORT Connect2, Connect3;
- FROM GtkUtils IMPORT Connect, CStrToM2;
- FROM GtkDemo IMPORT BuildByName, IsPorted;
- FROM DemoCatalog IMPORT DemoCatalogCount, DemoCatalogGet;
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM libc IMPORT printf;
- CONST
- AppId = "org.example.m2gtk4.Demo4";
- Invalid = 0FFFFFFFFH;
- VAR
- window, filter, filterModel, selection, infoTitle, infoBody, infoStatus,
- searchEntry: ADDRESS;
- query: ARRAY [0..63] OF CHAR;
- PROCEDURE Contains (hay, needle: ARRAY OF CHAR) : BOOLEAN;
- VAR
- i, j, hl, nl: CARDINAL;
- found: BOOLEAN;
- BEGIN
- hl := 0;
- WHILE (hl <= HIGH(hay)) AND (hay[hl] # 0C) DO INC(hl) END;
- nl := 0;
- WHILE (nl <= HIGH(needle)) AND (needle[nl] # 0C) DO INC(nl) END;
- IF nl = 0 THEN RETURN TRUE END;
- IF nl > hl THEN RETURN FALSE END;
- i := 0;
- WHILE i + nl <= hl DO
- found := TRUE;
- j := 0;
- WHILE j < nl DO
- IF hay[i + j] # needle[j] THEN found := FALSE END;
- INC(j)
- END;
- IF found THEN RETURN TRUE END;
- INC(i)
- END;
- RETURN FALSE
- END Contains;
- PROCEDURE CopyStr (VAR dst: ARRAY OF CHAR; src: ARRAY OF CHAR);
- VAR
- i: CARDINAL;
- BEGIN
- i := 0;
- WHILE (i <= HIGH(dst)) AND (i <= HIGH(src)) AND (src[i] # 0C) DO
- dst[i] := src[i];
- INC(i)
- END;
- IF i <= HIGH(dst) THEN dst[i] := 0C END
- END CopyStr;
- PROCEDURE LookupByName (name: ARRAY OF CHAR;
- VAR title, keywords, description: ARRAY OF CHAR);
- VAR
- i: CARDINAL;
- n, t, k, d: ARRAY [0..511] OF CHAR;
- BEGIN
- i := 0;
- WHILE i < DemoCatalogCount() DO
- DemoCatalogGet(i, n, t, k, d);
- IF Contains(n, name) AND Contains(name, n) THEN
- CopyStr(title, t); CopyStr(keywords, k); CopyStr(description, d);
- RETURN
- END;
- INC(i)
- END;
- title[0] := 0C; keywords[0] := 0C; description[0] := 0C
- END LookupByName;
- (* gboolean match(gpointer item, gpointer user) - item is a demo name *)
- PROCEDURE Match (item: ADDRESS; user: ADDRESS) : INTEGER;
- VAR
- name, title, keywords, description: ARRAY [0..511] OF CHAR;
- BEGIN
- CStrToM2(gtk_string_object_get_string(item), name);
- LookupByName(name, title, keywords, description);
- IF Contains(title, query) OR Contains(keywords, query) THEN
- RETURN 1
- ELSE
- RETURN 0
- END
- END Match;
- PROCEDURE UpdateInfo (name: ARRAY OF CHAR);
- VAR
- title, keywords, description: ARRAY [0..1023] OF CHAR;
- BEGIN
- LookupByName(name, title, keywords, description);
- gtk_label_set_text(infoTitle, title);
- gtk_label_set_text(infoBody, description);
- IF IsPorted(name) THEN
- gtk_label_set_text(infoStatus, "Ported to Modula-2. Press Run.")
- ELSE
- gtk_label_set_text(infoStatus, "Not ported yet.")
- END
- END UpdateInfo;
- PROCEDURE NameAtSelection (VAR name: ARRAY OF CHAR);
- VAR
- index: CARDINAL;
- item: ADDRESS;
- BEGIN
- name[0] := 0C;
- index := gtk_single_selection_get_selected(selection);
- IF index # Invalid THEN
- item := g_list_model_get_item(filterModel, index);
- CStrToM2(gtk_string_object_get_string(item), name);
- g_object_unref(item)
- END
- END NameAtSelection;
- PROCEDURE RunSelected;
- VAR
- name: ARRAY [0..511] OF CHAR;
- demoWindow: ADDRESS;
- BEGIN
- NameAtSelection(name);
- IF name[0] # 0C THEN
- UpdateInfo(name);
- IF IsPorted(name) THEN
- demoWindow := BuildByName(name, window);
- IF demoWindow = NIL THEN
- printf("demo %s could not be built\n", name)
- END
- END
- END
- END RunSelected;
- (* void activate(GtkListView *list, guint position, gpointer user) *)
- PROCEDURE OnActivate (list: ADDRESS; position: CARDINAL; user: ADDRESS);
- VAR
- item, demoWindow: ADDRESS;
- name: ARRAY [0..511] OF CHAR;
- BEGIN
- item := g_list_model_get_item(filterModel, position);
- CStrToM2(gtk_string_object_get_string(item), name);
- g_object_unref(item);
- UpdateInfo(name);
- IF IsPorted(name) THEN
- demoWindow := BuildByName(name, window)
- END
- END OnActivate;
- PROCEDURE OnRun (button: ADDRESS; user: ADDRESS);
- BEGIN
- RunSelected
- END OnRun;
- PROCEDURE OnSelectionChanged (sel: ADDRESS; user: ADDRESS);
- BEGIN
- RunSelected
- END OnSelectionChanged;
- PROCEDURE OnSearchChanged (entry: ADDRESS; user: ADDRESS);
- BEGIN
- CStrToM2(gtk_editable_get_text(entry), query);
- gtk_custom_filter_set_filter_func(filter, ADR(Match), NIL, NIL)
- END OnSearchChanged;
- PROCEDURE RowSetup (factory: ADDRESS; item: ADDRESS; user: ADDRESS);
- BEGIN
- gtk_list_item_set_child(item, gtk_label_new(""))
- END RowSetup;
- PROCEDURE RowBind (factory: ADDRESS; item: ADDRESS; user: ADDRESS);
- VAR
- obj, child: ADDRESS;
- name, title, keywords, description: ARRAY [0..511] OF CHAR;
- BEGIN
- obj := gtk_list_item_get_item(item);
- CStrToM2(gtk_string_object_get_string(obj), name);
- LookupByName(name, title, keywords, description);
- child := gtk_list_item_get_child(item);
- gtk_label_set_text(child, title)
- END RowBind;
- PROCEDURE OnActivateApp (application: ADDRESS; data: ADDRESS);
- VAR
- root, paned, sidebar, listView, factory, store, runButton, info: ADDRESS;
- name, title, keywords, description: ARRAY [0..511] OF CHAR;
- i: CARDINAL;
- BEGIN
- query[0] := 0C;
- store := gtk_string_list_new(NIL);
- i := 0;
- WHILE i < DemoCatalogCount() DO
- DemoCatalogGet(i, name, title, keywords, description);
- gtk_string_list_append(store, name);
- INC(i)
- END;
- filter := gtk_custom_filter_new(ADR(Match), NIL, NIL);
- filterModel := gtk_filter_list_model_new(store, filter);
- selection := gtk_single_selection_new(filterModel);
- factory := gtk_signal_list_item_factory_new();
- Connect3(factory, "setup", RowSetup, NIL);
- Connect3(factory, "bind", RowBind, NIL);
- listView := gtk_list_view_new(selection, factory);
- gtk_widget_set_vexpand(listView, 1);
- g_signal_connect_data(listView, "activate", ADR(OnActivate), NIL, NIL,
- GConnectDefault);
- Connect2(selection, "notify::selected", OnSelectionChanged, NIL);
- searchEntry := gtk_search_entry_new();
- gtk_search_entry_set_placeholder_text(searchEntry, "Search demos");
- Connect2(searchEntry, "search-changed", OnSearchChanged, NIL);
- sidebar := gtk_box_new(GtkVertical, 6);
- gtk_box_set_spacing(sidebar, 6);
- gtk_box_append(sidebar, searchEntry);
- gtk_box_append(sidebar, listView);
- gtk_widget_set_size_request(sidebar, 240, -1);
- infoTitle := gtk_label_new("");
- gtk_label_set_wrap(infoTitle, 1);
- gtk_label_set_max_width_chars(infoTitle, 40);
- gtk_widget_set_margin_start(infoTitle, 12);
- gtk_widget_set_margin_end(infoTitle, 12);
- gtk_widget_set_margin_top(infoTitle, 12);
- infoBody := gtk_label_new("");
- gtk_label_set_wrap(infoBody, 1);
- gtk_label_set_max_width_chars(infoBody, 50);
- gtk_widget_set_margin_start(infoBody, 12);
- gtk_widget_set_margin_end(infoBody, 12);
- infoStatus := gtk_label_new("");
- gtk_label_set_wrap(infoStatus, 1);
- gtk_widget_set_margin_start(infoStatus, 12);
- gtk_widget_set_margin_end(infoStatus, 12);
- runButton := gtk_button_new_with_label("Run selected demo");
- gtk_widget_set_margin_start(runButton, 12);
- gtk_widget_set_margin_end(runButton, 12);
- gtk_widget_set_margin_bottom(runButton, 12);
- Connect2(runButton, "clicked", OnRun, NIL);
- info := gtk_box_new(GtkVertical, 10);
- gtk_box_set_spacing(info, 10);
- gtk_box_append(info, infoTitle);
- gtk_box_append(info, infoBody);
- gtk_box_append(info, infoStatus);
- gtk_box_append(info, runButton);
- paned := gtk_paned_new(GtkHorizontal);
- gtk_paned_set_start_child(paned, sidebar);
- gtk_paned_set_end_child(paned, info);
- gtk_paned_set_position(paned, 260);
- root := gtk_box_new(GtkVertical, 0);
- gtk_box_append(root, paned);
- window := gtk_application_window_new(application);
- gtk_window_set_title(window, "m2-GTK4 Demo");
- gtk_window_set_default_size(window, 760, 520);
- gtk_window_set_child(window, root);
- gtk_window_present(window)
- END OnActivateApp;
- VAR
- app: ADDRESS;
- BEGIN
- app := gtk_application_new(AppId, 0);
- IF app = NIL THEN
- printf("gtk_application_new failed\n");
- HALT(1)
- END;
- Connect2(app, "activate", OnActivateApp, NIL);
- g_application_run(app, 0, NIL)
- END m2gtkdemo.
|