| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- IMPLEMENTATION MODULE DemosInput ;
- (*
- See the GTK C originals in gtk/demos/gtk-demo:
- password_entry.c, search_entry.c, tagged_entry.c, shortcut_triggers.c
- Only the bindings under src/ are used, so this module builds with just
- -Isrc -Idemos (see also demos/DemosText.mod). A few C facilities used
- by the originals are not bound; those spots are simplified and called
- out in comments:
- * GtkPasswordEntry is not bound, so the two password fields use a
- GtkEntry with visibility switched off (still read via GtkEditable).
- * gtk_search_bar_set_key_capture_widget / g_object_bind_property are
- not bound; the header toggle drives the search bar through its
- "toggled" signal instead.
- * the demo-private DemoTaggedEntry composite is not a GTK widget, so
- the tagged entry is approximated with a GtkBox holding an entry,
- tag labels and a spinner.
- * gtk_callback_action_new is not bound; the shortcut rows are
- GtkButtons and the parsed "signal(clicked)" action activates them.
- *)
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM GtkWindow IMPORT gtk_window_new, gtk_window_set_title,
- gtk_window_set_default_size, gtk_window_set_resizable,
- gtk_window_set_titlebar, gtk_window_set_child, gtk_window_destroy;
- FROM GtkWidget IMPORT gtk_widget_set_visible, gtk_widget_get_visible,
- gtk_widget_set_margin_start, gtk_widget_set_margin_end,
- gtk_widget_set_margin_top, gtk_widget_set_margin_bottom,
- gtk_widget_set_sensitive, gtk_widget_set_halign,
- gtk_widget_set_size_request, gtk_widget_add_css_class,
- gtk_widget_add_controller;
- FROM GtkEnums IMPORT GtkVertical, GtkHorizontal, GtkAlignCenter, GtkAlignEnd;
- FROM GtkBox IMPORT gtk_box_new, gtk_box_append, gtk_box_remove;
- FROM GtkHeaderBar IMPORT gtk_header_bar_new,
- gtk_header_bar_set_show_title_buttons, gtk_header_bar_pack_end;
- FROM GtkEntry IMPORT gtk_entry_new, gtk_entry_set_placeholder_text;
- FROM GtkPasswordEntry IMPORT gtk_password_entry_new;
- FROM GtkEditable IMPORT gtk_editable_get_text;
- FROM GtkSearchEntry IMPORT gtk_search_entry_new;
- FROM GtkSearchBar IMPORT gtk_search_bar_new, gtk_search_bar_connect_entry,
- gtk_search_bar_set_show_close_button, gtk_search_bar_set_child,
- gtk_search_bar_set_search_mode;
- FROM GtkToggleButton IMPORT gtk_toggle_button_new_with_label,
- gtk_toggle_button_get_active;
- FROM GtkButton IMPORT gtk_button_new_with_label,
- gtk_button_new_with_mnemonic, gtk_button_get_label;
- FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_text;
- FROM GtkCheckButton IMPORT gtk_check_button_new_with_mnemonic;
- FROM GtkSpinner IMPORT gtk_spinner_new, gtk_spinner_start;
- FROM GtkListBox IMPORT gtk_list_box_new, gtk_list_box_insert;
- FROM GtkShortcut IMPORT gtk_shortcut_new,
- gtk_shortcut_trigger_parse_string, gtk_shortcut_action_parse_string;
- FROM GtkShortcutController IMPORT gtk_shortcut_controller_new,
- gtk_shortcut_controller_set_scope, gtk_shortcut_controller_add_shortcut,
- GtkShortcutScopeGlobal;
- FROM GObject IMPORT g_signal_connect_data, GConnectDefault;
- FROM GLib IMPORT g_strcmp0;
- FROM libc IMPORT printf, strncpy;
- (* local stand-in for GtkUtils.CStrToM2 (lib/ is not on the include path
- for these demos): copy a borrowed C string into a Modula-2 buffer. *)
- PROCEDURE CopyCStr (src: ADDRESS; VAR dst: ARRAY OF CHAR);
- BEGIN
- IF src = NIL THEN
- dst[0] := 0C
- ELSE
- strncpy(ADR(dst), src, HIGH(dst) + 1);
- dst[HIGH(dst)] := 0C
- END
- END CopyCStr;
- (* ------------------------------------------------------------------ *)
- (* Password Entry *)
- (* ------------------------------------------------------------------ *)
- VAR
- pwWindow, pwEntry, pwEntry2, pwButton: ADDRESS;
- (* void update_button(GObject *object, GParamSpec *pspec, gpointer data) *)
- PROCEDURE OnUpdateButton (object: ADDRESS; pspec: ADDRESS; data: ADDRESS);
- VAR
- text, text2: ADDRESS;
- buf: ARRAY [0..255] OF CHAR;
- BEGIN
- text := gtk_editable_get_text(pwEntry);
- text2 := gtk_editable_get_text(pwEntry2);
- CopyCStr(text, buf);
- IF (buf[0] # 0C) AND (g_strcmp0(text, text2) = 0) THEN
- gtk_widget_set_sensitive(pwButton, 1)
- ELSE
- gtk_widget_set_sensitive(pwButton, 0)
- END
- END OnUpdateButton;
- (* void button_pressed(GtkButton *widget, GtkWidget *window) *)
- PROCEDURE OnDone (button: ADDRESS; data: ADDRESS);
- BEGIN
- gtk_window_destroy(pwWindow);
- pwWindow := NIL
- END OnDone;
- PROCEDURE PasswordField (placeholder: ARRAY OF CHAR) : ADDRESS;
- VAR
- entry: ADDRESS;
- BEGIN
- entry := gtk_password_entry_new();
- g_signal_connect_data(entry, "notify::text", ADR(OnUpdateButton),
- NIL, NIL, GConnectDefault);
- RETURN entry
- END PasswordField;
- PROCEDURE DoPasswordEntry (doWidget: ADDRESS) : ADDRESS;
- VAR
- box, header: ADDRESS;
- BEGIN
- IF pwWindow = NIL THEN
- pwWindow := gtk_window_new();
- gtk_window_set_title(pwWindow, "Choose a Password");
- gtk_window_set_resizable(pwWindow, 0);
- header := gtk_header_bar_new();
- gtk_header_bar_set_show_title_buttons(header, 0);
- gtk_window_set_titlebar(pwWindow, header);
- box := gtk_box_new(GtkVertical, 6);
- gtk_widget_set_margin_start(box, 18);
- gtk_widget_set_margin_end(box, 18);
- gtk_widget_set_margin_top(box, 18);
- gtk_widget_set_margin_bottom(box, 18);
- gtk_window_set_child(pwWindow, box);
- pwEntry := PasswordField("Password");
- gtk_box_append(box, pwEntry);
- pwEntry2 := PasswordField("Confirm");
- gtk_box_append(box, pwEntry2);
- pwButton := gtk_button_new_with_mnemonic("_Done");
- gtk_widget_add_css_class(pwButton, "suggested-action");
- g_signal_connect_data(pwButton, "clicked", ADR(OnDone),
- NIL, NIL, GConnectDefault);
- gtk_widget_set_sensitive(pwButton, 0);
- gtk_header_bar_pack_end(header, pwButton)
- END;
- IF gtk_widget_get_visible(pwWindow) = 0 THEN
- gtk_widget_set_visible(pwWindow, 1)
- ELSE
- gtk_window_destroy(pwWindow);
- pwWindow := NIL
- END;
- RETURN pwWindow
- END DoPasswordEntry;
- (* ------------------------------------------------------------------ *)
- (* Search Entry *)
- (* ------------------------------------------------------------------ *)
- VAR
- searchWindow, searchBar: ADDRESS;
- (* void search_changed_cb(GtkSearchEntry *entry, GtkLabel *result_label) *)
- PROCEDURE OnSearchChanged (entry: ADDRESS; resultLabel: ADDRESS);
- VAR
- text: ADDRESS;
- buf: ARRAY [0..255] OF CHAR;
- BEGIN
- text := gtk_editable_get_text(entry);
- CopyCStr(text, buf);
- gtk_label_set_text(resultLabel, buf)
- END OnSearchChanged;
- (* The C demo binds the header toggle's "active" to the search bar's
- "search-mode-enabled"; g_object_bind_property is not bound here, so
- the same effect is wired through the "toggled" signal. *)
- PROCEDURE OnSearchToggled (button: ADDRESS; data: ADDRESS);
- BEGIN
- IF gtk_toggle_button_get_active(button) # 0 THEN
- gtk_search_bar_set_search_mode(searchBar, 1)
- ELSE
- gtk_search_bar_set_search_mode(searchBar, 0)
- END
- END OnSearchToggled;
- PROCEDURE DoSearchEntry (doWidget: ADDRESS) : ADDRESS;
- VAR
- vbox, hbox, box, label, entry, button, header: ADDRESS;
- BEGIN
- IF searchWindow = NIL THEN
- searchWindow := gtk_window_new();
- gtk_window_set_title(searchWindow, "Type to Search");
- gtk_window_set_resizable(searchWindow, 0);
- gtk_widget_set_size_request(searchWindow, 200, -1);
- header := gtk_header_bar_new();
- gtk_window_set_titlebar(searchWindow, header);
- vbox := gtk_box_new(GtkVertical, 0);
- gtk_window_set_child(searchWindow, vbox);
- entry := gtk_search_entry_new();
- gtk_widget_set_halign(entry, GtkAlignCenter);
- searchBar := gtk_search_bar_new();
- gtk_search_bar_connect_entry(searchBar, entry);
- gtk_search_bar_set_show_close_button(searchBar, 0);
- gtk_search_bar_set_child(searchBar, entry);
- gtk_box_append(vbox, searchBar);
- (* gtk_search_bar_set_key_capture_widget is not bound; the search
- bar is opened via the header toggle below instead. *)
- box := gtk_box_new(GtkVertical, 18);
- gtk_widget_set_margin_start(box, 18);
- gtk_widget_set_margin_end(box, 18);
- gtk_widget_set_margin_top(box, 18);
- gtk_widget_set_margin_bottom(box, 18);
- gtk_box_append(vbox, box);
- button := gtk_toggle_button_new_with_label("Search");
- g_signal_connect_data(button, "toggled", ADR(OnSearchToggled),
- NIL, NIL, GConnectDefault);
- gtk_header_bar_pack_end(header, button);
- hbox := gtk_box_new(GtkHorizontal, 10);
- gtk_box_append(box, hbox);
- label := gtk_label_new("Searching for:");
- gtk_box_append(hbox, label);
- label := gtk_label_new("");
- gtk_box_append(hbox, label);
- g_signal_connect_data(entry, "search-changed", ADR(OnSearchChanged),
- label, NIL, GConnectDefault)
- END;
- IF gtk_widget_get_visible(searchWindow) = 0 THEN
- gtk_widget_set_visible(searchWindow, 1)
- ELSE
- gtk_window_destroy(searchWindow);
- searchWindow := NIL
- END;
- RETURN searchWindow
- END DoSearchEntry;
- (* ------------------------------------------------------------------ *)
- (* Tagged Entry *)
- (* ------------------------------------------------------------------ *)
- (* The demo's DemoTaggedEntry composite is not bound; this approximates
- it with a horizontal GtkBox that holds the entry, tag labels and an
- optional spinner. *)
- VAR
- taggedWindow, tagBox, tagSpinner: ADDRESS;
- (* void add_tag(GtkButton *button, DemoTaggedEntry *entry) *)
- PROCEDURE OnAddTag (button: ADDRESS; data: ADDRESS);
- VAR
- tag: ADDRESS;
- BEGIN
- tag := gtk_label_new("Blue");
- gtk_widget_add_css_class(tag, "blue");
- gtk_box_append(tagBox, tag)
- END OnAddTag;
- (* void toggle_spinner(GtkCheckButton *button, DemoTaggedEntry *entry) *)
- PROCEDURE OnToggleSpinner (button: ADDRESS; data: ADDRESS);
- BEGIN
- IF tagSpinner = NIL THEN
- tagSpinner := gtk_spinner_new();
- gtk_spinner_start(tagSpinner);
- gtk_box_append(tagBox, tagSpinner)
- ELSE
- gtk_box_remove(tagBox, tagSpinner);
- tagSpinner := NIL
- END
- END OnToggleSpinner;
- PROCEDURE DoTaggedEntry (doWidget: ADDRESS) : ADDRESS;
- VAR
- box, box2, entry, button: ADDRESS;
- BEGIN
- IF taggedWindow = NIL THEN
- taggedWindow := gtk_window_new();
- gtk_window_set_title(taggedWindow, "Tagged Entry");
- gtk_window_set_default_size(taggedWindow, 260, -1);
- gtk_window_set_resizable(taggedWindow, 0);
- box := gtk_box_new(GtkVertical, 6);
- gtk_widget_set_margin_start(box, 18);
- gtk_widget_set_margin_end(box, 18);
- gtk_widget_set_margin_top(box, 18);
- gtk_widget_set_margin_bottom(box, 18);
- gtk_window_set_child(taggedWindow, box);
- tagBox := gtk_box_new(GtkHorizontal, 6);
- gtk_box_append(box, tagBox);
- entry := gtk_entry_new();
- gtk_box_append(tagBox, entry);
- box2 := gtk_box_new(GtkHorizontal, 6);
- gtk_widget_set_halign(box2, GtkAlignEnd);
- gtk_box_append(box, box2);
- button := gtk_button_new_with_mnemonic("Add _Tag");
- g_signal_connect_data(button, "clicked", ADR(OnAddTag),
- entry, NIL, GConnectDefault);
- gtk_box_append(box2, button);
- button := gtk_check_button_new_with_mnemonic("_Spinner");
- g_signal_connect_data(button, "toggled", ADR(OnToggleSpinner),
- entry, NIL, GConnectDefault);
- gtk_box_append(box2, button)
- END;
- IF gtk_widget_get_visible(taggedWindow) = 0 THEN
- gtk_widget_set_visible(taggedWindow, 1)
- ELSE
- gtk_window_destroy(taggedWindow);
- taggedWindow := NIL;
- tagBox := NIL;
- tagSpinner := NIL
- END;
- RETURN taggedWindow
- END DoTaggedEntry;
- (* ------------------------------------------------------------------ *)
- (* Shortcut Triggers *)
- (* ------------------------------------------------------------------ *)
- VAR
- shortcutWindow: ADDRESS;
- shortcutDesc: ARRAY [0..1] OF ARRAY [0..31] OF CHAR;
- shortcutTrig: ARRAY [0..1] OF ARRAY [0..31] OF CHAR;
- (* gboolean shortcut_activated(GtkWidget *widget, GVariant *unused, gpointer row) *)
- PROCEDURE OnShortcutActivated (button: ADDRESS; data: ADDRESS);
- VAR
- label: ADDRESS;
- buf: ARRAY [0..127] OF CHAR;
- BEGIN
- label := gtk_button_get_label(button);
- CopyCStr(label, buf);
- printf("activated %s\n", buf)
- END OnShortcutActivated;
- PROCEDURE DoShortcutTriggers (doWidget: ADDRESS) : ADDRESS;
- VAR
- list, row, controller, trigger, action, shortcut: ADDRESS;
- i: INTEGER;
- triggerAction: ARRAY [0..31] OF CHAR;
- BEGIN
- IF shortcutWindow = NIL THEN
- shortcutWindow := gtk_window_new();
- gtk_window_set_title(shortcutWindow, "Shortcuts");
- gtk_window_set_default_size(shortcutWindow, 200, -1);
- gtk_window_set_resizable(shortcutWindow, 0);
- shortcutDesc[0] := "Press Ctrl-G";
- shortcutDesc[1] := "Press X";
- shortcutTrig[0] := "<Control>g";
- shortcutTrig[1] := "x";
- triggerAction := "signal(clicked)";
- list := gtk_list_box_new();
- gtk_widget_set_margin_top(list, 6);
- gtk_widget_set_margin_bottom(list, 6);
- gtk_widget_set_margin_start(list, 6);
- gtk_widget_set_margin_end(list, 6);
- gtk_window_set_child(shortcutWindow, list);
- FOR i := 0 TO 1 DO
- (* The C row is a GtkLabel whose shortcut uses
- gtk_callback_action_new (not bound); a GtkButton row plus the
- parsed "signal(clicked)" action gives the same activation. *)
- row := gtk_button_new_with_label(shortcutDesc[i]);
- gtk_list_box_insert(list, row, -1);
- controller := gtk_shortcut_controller_new();
- gtk_shortcut_controller_set_scope(controller, GtkShortcutScopeGlobal);
- gtk_widget_add_controller(row, controller);
- trigger := gtk_shortcut_trigger_parse_string(shortcutTrig[i]);
- action := gtk_shortcut_action_parse_string(triggerAction);
- shortcut := gtk_shortcut_new(trigger, action);
- gtk_shortcut_controller_add_shortcut(controller, shortcut);
- g_signal_connect_data(row, "clicked", ADR(OnShortcutActivated),
- NIL, NIL, GConnectDefault)
- END
- END;
- IF gtk_widget_get_visible(shortcutWindow) = 0 THEN
- gtk_widget_set_visible(shortcutWindow, 1)
- ELSE
- gtk_window_destroy(shortcutWindow);
- shortcutWindow := NIL
- END;
- RETURN shortcutWindow
- END DoShortcutTriggers;
- END DemosInput.
|