IMPLEMENTATION MODULE DemosChooser ; (* See the GTK C originals in gtk/demos/gtk-demo: combobox.c -> DoComboBox entry_completion.c -> DoEntryCompletion entry_undo.c -> DoEntryUndo dialog.c -> DoDialog The gtk-demo contract is: on the first call build the window and store it in a module-level variable; on later calls just toggle the window's visibility, destroying it (and clearing the variable) when it is already visible. Return the window, or NIL once destroyed. None of the deprecated, model-based widgets these demos use are exposed under src/ (GtkComboBox, GtkComboBoxText, GtkTreeModel, GtkListStore, GtkTreeStore, GtkCellRenderer, GtkCellLayout), and neither are GtkDialog / GtkMessageDialog. Each affected spot is adapted to a bound equivalent and marked SIMPLIFIED below: * combobox: the four combo boxes become GtkDropDown widgets over a GtkStringList (the documented modern replacement). The icon renderer, the row separator, the insensitive rows and the GtkTreeStore hierarchy cannot be reproduced, so the "Items with icons" frame lists its five labels and the "Where are we ?" frame lists the capitals of its tree flattened. The editable combo is a drop-down with search enabled; the "String IDs" property binding (g_object_bind_property, unbound) is emulated by wiring the drop-down's "notify::selected" and the entry's "changed" signals together. * entry_completion: GtkEntryCompletion is bound, but the GtkTreeModel/GtkListStore it needs for its items is not, so the completion is created with a text column but no model. The inline-completion and inline-selection setters are not bound either. * entry_undo: gtk_editable_set_enable_undo() is not bound, so the entry is created without enabling undo/redo. * dialog: GtkDialog/GtkMessageDialog are replaced by AdwMessageDialog (responses plus an extra child); plain labels stand in for the mnemonic labels, whose setters (gtk_label_new_with_mnemonic / gtk_label_set_mnemonic_widget) are not bound. *) FROM SYSTEM IMPORT ADDRESS, ADR; FROM GtkWindow IMPORT gtk_window_new, gtk_window_set_title, gtk_window_set_resizable, gtk_window_set_child, gtk_window_destroy, gtk_window_present; 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_hexpand, gtk_widget_set_vexpand, gtk_widget_set_halign, gtk_widget_set_valign; FROM GtkEnums IMPORT GtkVertical, GtkHorizontal, GtkAlignCenter; FROM GtkBox IMPORT gtk_box_new, gtk_box_append; FROM GtkFrame IMPORT gtk_frame_new, gtk_frame_set_child; FROM GtkLabel IMPORT gtk_label_new, gtk_label_set_markup; FROM GtkGrid IMPORT gtk_grid_new, gtk_grid_attach, gtk_grid_set_row_spacing, gtk_grid_set_column_spacing; FROM GtkSeparator IMPORT gtk_separator_new; FROM GtkButton IMPORT gtk_button_new_with_mnemonic; FROM GtkEntry IMPORT gtk_entry_new, gtk_entry_set_completion; FROM GtkEntryCompletion IMPORT gtk_entry_completion_new, gtk_entry_completion_set_text_column, gtk_entry_completion_set_popup_completion; FROM GtkEditable IMPORT gtk_editable_get_text, gtk_editable_set_text; FROM GtkDropDown IMPORT gtk_drop_down_new, gtk_drop_down_set_selected, gtk_drop_down_get_selected, gtk_drop_down_get_model, gtk_drop_down_set_enable_search; FROM GtkStringList IMPORT gtk_string_list_new, gtk_string_list_append, gtk_string_list_get_string; FROM AdwMessageDialog IMPORT adw_message_dialog_new, adw_message_dialog_add_response, adw_message_dialog_set_default_response, adw_message_dialog_set_extra_child; FROM GtkClosures IMPORT Connect2, Connect3; FROM GtkUtils IMPORT IntToStr, CStrToM2, StrAppend; FROM GLib IMPORT g_strcmp0; (* ================================================================== *) (* combobox *) (* ================================================================== *) VAR comboWindow: ADDRESS; comboStringEntry: ADDRESS; (* entry of the "String IDs" frame *) comboIdsDropDown: ADDRESS; (* drop-down of the "String IDs" frame *) (* Keep the two sides of the (unbound) active-id <-> text property binding in sync: selecting a drop-down item writes the entry, and typing an exact item writes the drop-down. *) PROCEDURE OnComboSelected (dropdown: ADDRESS; pspec: ADDRESS; data: ADDRESS); VAR model, item: ADDRESS; buf: ARRAY [0..63] OF CHAR; BEGIN model := gtk_drop_down_get_model(dropdown); item := gtk_string_list_get_string(model, gtk_drop_down_get_selected(dropdown)); CStrToM2(item, buf); gtk_editable_set_text(comboStringEntry, buf) END OnComboSelected; PROCEDURE OnComboEntryChanged (entry: ADDRESS; data: ADDRESS); VAR model, item: ADDRESS; text, buf: ARRAY [0..63] OF CHAR; i: INTEGER; BEGIN CStrToM2(gtk_editable_get_text(entry), text); model := gtk_drop_down_get_model(comboIdsDropDown); FOR i := 0 TO 2 DO item := gtk_string_list_get_string(model, VAL(CARDINAL, i)); CStrToM2(item, buf); IF g_strcmp0(ADR(text), ADR(buf)) = 0 THEN gtk_drop_down_set_selected(comboIdsDropDown, VAL(CARDINAL, i)); RETURN END END END OnComboEntryChanged; (* The capitals of create_capital_store(), flattened (the group rows and the tree shape are lost with GtkTreeStore unbound). Index 8 is Boston, which is what the C demo selects via path (0, 8). *) PROCEDURE AddCapitals (list: ADDRESS); BEGIN gtk_string_list_append(list, "Albany"); gtk_string_list_append(list, "Annapolis"); gtk_string_list_append(list, "Atlanta"); gtk_string_list_append(list, "Augusta"); gtk_string_list_append(list, "Austin"); gtk_string_list_append(list, "Baton Rouge"); gtk_string_list_append(list, "Bismarck"); gtk_string_list_append(list, "Boise"); gtk_string_list_append(list, "Boston"); gtk_string_list_append(list, "Carson City"); gtk_string_list_append(list, "Charleston"); gtk_string_list_append(list, "Cheyenne"); gtk_string_list_append(list, "Columbia"); gtk_string_list_append(list, "Columbus"); gtk_string_list_append(list, "Concord"); gtk_string_list_append(list, "Denver"); gtk_string_list_append(list, "Des Moines"); gtk_string_list_append(list, "Dover"); gtk_string_list_append(list, "Frankfort"); gtk_string_list_append(list, "Harrisburg"); gtk_string_list_append(list, "Hartford"); gtk_string_list_append(list, "Helena"); gtk_string_list_append(list, "Honolulu"); gtk_string_list_append(list, "Indianapolis"); gtk_string_list_append(list, "Jackson"); gtk_string_list_append(list, "Jefferson City"); gtk_string_list_append(list, "Juneau"); gtk_string_list_append(list, "Lansing"); gtk_string_list_append(list, "Lincoln"); gtk_string_list_append(list, "Little Rock"); gtk_string_list_append(list, "Madison"); gtk_string_list_append(list, "Montgomery"); gtk_string_list_append(list, "Montpelier"); gtk_string_list_append(list, "Nashville"); gtk_string_list_append(list, "Oklahoma City"); gtk_string_list_append(list, "Olympia"); gtk_string_list_append(list, "Phoenix"); gtk_string_list_append(list, "Pierre"); gtk_string_list_append(list, "Providence"); gtk_string_list_append(list, "Raleigh"); gtk_string_list_append(list, "Richmond"); gtk_string_list_append(list, "Sacramento"); gtk_string_list_append(list, "Salem"); gtk_string_list_append(list, "Salt Lake City"); gtk_string_list_append(list, "Santa Fe"); gtk_string_list_append(list, "Springfield"); gtk_string_list_append(list, "St. Paul"); gtk_string_list_append(list, "Tallahassee"); gtk_string_list_append(list, "Topeka"); gtk_string_list_append(list, "Trenton") END AddCapitals; PROCEDURE DoComboBox (doWidget: ADDRESS) : ADDRESS; VAR vbox, frame, box, combo, list: ADDRESS; BEGIN IF comboWindow = NIL THEN comboWindow := gtk_window_new(); gtk_window_set_title(comboWindow, "Combo Boxes"); vbox := gtk_box_new(GtkVertical, 2); gtk_widget_set_margin_start(vbox, 10); gtk_widget_set_margin_end(vbox, 10); gtk_widget_set_margin_top(vbox, 10); gtk_widget_set_margin_bottom(vbox, 10); gtk_window_set_child(comboWindow, vbox); (* Items with icons (icons, separator and insensitivity omitted) *) frame := gtk_frame_new("Items with icons"); gtk_box_append(vbox, frame); box := gtk_box_new(GtkVertical, 0); gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_end(box, 5); gtk_widget_set_margin_top(box, 5); gtk_widget_set_margin_bottom(box, 5); gtk_frame_set_child(frame, box); list := gtk_string_list_new(NIL); gtk_string_list_append(list, "Warning"); gtk_string_list_append(list, "Stop"); gtk_string_list_append(list, "New"); gtk_string_list_append(list, "Clear"); gtk_string_list_append(list, "Open"); combo := gtk_drop_down_new(list, NIL); gtk_drop_down_set_selected(combo, 0); gtk_box_append(box, combo); (* Where are we ? (tree flattened to its capitals) *) frame := gtk_frame_new("Where are we ?"); gtk_box_append(vbox, frame); box := gtk_box_new(GtkVertical, 0); gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_end(box, 5); gtk_widget_set_margin_top(box, 5); gtk_widget_set_margin_bottom(box, 5); gtk_frame_set_child(frame, box); list := gtk_string_list_new(NIL); AddCapitals(list); combo := gtk_drop_down_new(list, NIL); gtk_drop_down_set_selected(combo, 8); gtk_box_append(box, combo); (* Editable (search stands in for the validating entry) *) frame := gtk_frame_new("Editable"); gtk_box_append(vbox, frame); box := gtk_box_new(GtkVertical, 0); gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_end(box, 5); gtk_widget_set_margin_top(box, 5); gtk_widget_set_margin_bottom(box, 5); gtk_frame_set_child(frame, box); list := gtk_string_list_new(NIL); gtk_string_list_append(list, "One"); gtk_string_list_append(list, "Two"); gtk_string_list_append(list, "2\xC2\xBD"); gtk_string_list_append(list, "Three"); combo := gtk_drop_down_new(list, NIL); gtk_drop_down_set_enable_search(combo, 1); gtk_box_append(box, combo); (* String IDs (active-id binding emulated with two signals) *) frame := gtk_frame_new("String IDs"); gtk_box_append(vbox, frame); box := gtk_box_new(GtkVertical, 0); gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_end(box, 5); gtk_widget_set_margin_top(box, 5); gtk_widget_set_margin_bottom(box, 5); gtk_frame_set_child(frame, box); list := gtk_string_list_new(NIL); gtk_string_list_append(list, "Not visible"); gtk_string_list_append(list, "Visible when active"); gtk_string_list_append(list, "Always visible"); comboIdsDropDown := gtk_drop_down_new(list, NIL); gtk_box_append(box, comboIdsDropDown); comboStringEntry := gtk_entry_new(); gtk_box_append(box, comboStringEntry); Connect3(comboIdsDropDown, "notify::selected", OnComboSelected, NIL); Connect2(comboStringEntry, "changed", OnComboEntryChanged, NIL) END; IF gtk_widget_get_visible(comboWindow) = 0 THEN gtk_widget_set_visible(comboWindow, 1) ELSE gtk_window_destroy(comboWindow); comboWindow := NIL; comboStringEntry := NIL; comboIdsDropDown := NIL END; RETURN comboWindow END DoComboBox; (* ================================================================== *) (* entry_completion *) (* ================================================================== *) VAR entryCompletionWindow: ADDRESS; PROCEDURE DoEntryCompletion (doWidget: ADDRESS) : ADDRESS; VAR vbox, label, entry, completion: ADDRESS; BEGIN IF entryCompletionWindow = NIL THEN entryCompletionWindow := gtk_window_new(); gtk_window_set_title(entryCompletionWindow, "Completion"); gtk_window_set_resizable(entryCompletionWindow, 0); vbox := gtk_box_new(GtkVertical, 12); gtk_widget_set_margin_start(vbox, 18); gtk_widget_set_margin_end(vbox, 18); gtk_widget_set_margin_top(vbox, 18); gtk_widget_set_margin_bottom(vbox, 18); gtk_window_set_child(entryCompletionWindow, vbox); label := gtk_label_new(""); gtk_label_set_markup(label, "Try writing total or gnome for example."); gtk_box_append(vbox, label); entry := gtk_entry_new(); gtk_box_append(vbox, entry); completion := gtk_entry_completion_new(); gtk_entry_set_completion(entry, completion); (* SIMPLIFIED: GtkTreeModel/GtkListStore (the completion's model) are unbound, so there are no items to complete; only the text column and popup-completion setting survive. The C demo's inline-completion/inline-selection setters are unbound too. *) gtk_entry_completion_set_text_column(completion, 0); gtk_entry_completion_set_popup_completion(completion, 1) END; IF gtk_widget_get_visible(entryCompletionWindow) = 0 THEN gtk_widget_set_visible(entryCompletionWindow, 1) ELSE gtk_window_destroy(entryCompletionWindow); entryCompletionWindow := NIL END; RETURN entryCompletionWindow END DoEntryCompletion; (* ================================================================== *) (* entry_undo *) (* ================================================================== *) VAR entryUndoWindow: ADDRESS; PROCEDURE DoEntryUndo (doWidget: ADDRESS) : ADDRESS; VAR vbox, label, entry: ADDRESS; BEGIN IF entryUndoWindow = NIL THEN entryUndoWindow := gtk_window_new(); gtk_window_set_title(entryUndoWindow, "Undo and Redo"); gtk_window_set_resizable(entryUndoWindow, 0); vbox := gtk_box_new(GtkVertical, 12); gtk_widget_set_margin_start(vbox, 18); gtk_widget_set_margin_end(vbox, 18); gtk_widget_set_margin_top(vbox, 18); gtk_widget_set_margin_bottom(vbox, 18); gtk_window_set_child(entryUndoWindow, vbox); label := gtk_label_new(""); gtk_label_set_markup(label, "Use Control+z or Control+Shift+z to undo or redo changes"); gtk_box_append(vbox, label); entry := gtk_entry_new(); (* SIMPLIFIED: gtk_editable_set_enable_undo() is not bound, so undo/redo support cannot be turned on from here. *) gtk_box_append(vbox, entry) END; IF gtk_widget_get_visible(entryUndoWindow) = 0 THEN gtk_widget_set_visible(entryUndoWindow, 1) ELSE gtk_window_destroy(entryUndoWindow); entryUndoWindow := NIL END; RETURN entryUndoWindow END DoEntryUndo; (* ================================================================== *) (* dialog *) (* ================================================================== *) VAR dialogWindow: ADDRESS; dialogEntry1, dialogEntry2: ADDRESS; (* left-hand entries *) dialogLocalEntry1, dialogLocalEntry2: ADDRESS; dialogCount: INTEGER; (* void message_dialog_clicked(GtkButton *button, gpointer user_data) *) PROCEDURE OnMessageDialog (button: ADDRESS; data: ADDRESS); VAR dialog: ADDRESS; body, num: ARRAY [0..63] OF CHAR; BEGIN INC(dialogCount); body := "Has been shown "; IntToStr(dialogCount, num); StrAppend(body, num); StrAppend(body, " times"); dialog := adw_message_dialog_new(dialogWindow, "Test message", body); adw_message_dialog_add_response(dialog, "ok", "_OK"); adw_message_dialog_add_response(dialog, "cancel", "_Cancel"); adw_message_dialog_set_default_response(dialog, "ok"); gtk_window_present(dialog) END OnMessageDialog; (* void on_dialog_response(GtkDialog *dialog, int response, gpointer data) *) PROCEDURE OnDialogResponse (dialog: ADDRESS; response: ADDRESS; data: ADDRESS); VAR ok: ARRAY [0..3] OF CHAR; text: ARRAY [0..255] OF CHAR; BEGIN ok := "ok"; IF g_strcmp0(response, ADR(ok)) = 0 THEN CStrToM2(gtk_editable_get_text(dialogLocalEntry1), text); gtk_editable_set_text(dialogEntry1, text); CStrToM2(gtk_editable_get_text(dialogLocalEntry2), text); gtk_editable_set_text(dialogEntry2, text) END (* AdwMessageDialog closes itself once a response is activated. *) END OnDialogResponse; (* void interactive_dialog_clicked(GtkButton *button, gpointer user_data) *) PROCEDURE OnInteractiveDialog (button: ADDRESS; data: ADDRESS); VAR dialog, grid, label: ADDRESS; text: ARRAY [0..255] OF CHAR; BEGIN dialog := adw_message_dialog_new(dialogWindow, "Interactive Dialog", ""); adw_message_dialog_add_response(dialog, "ok", "_OK"); adw_message_dialog_add_response(dialog, "cancel", "_Cancel"); adw_message_dialog_set_default_response(dialog, "ok"); grid := gtk_grid_new(); gtk_widget_set_hexpand(grid, 1); gtk_widget_set_vexpand(grid, 1); gtk_widget_set_halign(grid, GtkAlignCenter); gtk_widget_set_valign(grid, GtkAlignCenter); gtk_grid_set_row_spacing(grid, 6); gtk_grid_set_column_spacing(grid, 6); (* SIMPLIFIED: plain labels, as the mnemonic variants are unbound. *) label := gtk_label_new("Entry 1"); gtk_grid_attach(grid, label, 0, 0, 1, 1); dialogLocalEntry1 := gtk_entry_new(); CStrToM2(gtk_editable_get_text(dialogEntry1), text); gtk_editable_set_text(dialogLocalEntry1, text); gtk_grid_attach(grid, dialogLocalEntry1, 1, 0, 1, 1); label := gtk_label_new("Entry 2"); gtk_grid_attach(grid, label, 0, 1, 1, 1); dialogLocalEntry2 := gtk_entry_new(); CStrToM2(gtk_editable_get_text(dialogEntry2), text); gtk_editable_set_text(dialogLocalEntry2, text); gtk_grid_attach(grid, dialogLocalEntry2, 1, 1, 1, 1); adw_message_dialog_set_extra_child(dialog, grid); Connect3(dialog, "response", OnDialogResponse, NIL); gtk_window_present(dialog) END OnInteractiveDialog; PROCEDURE DoDialog (doWidget: ADDRESS) : ADDRESS; VAR vbox, vbox2, hbox, button, table, label: ADDRESS; BEGIN IF dialogWindow = NIL THEN dialogWindow := gtk_window_new(); gtk_window_set_title(dialogWindow, "Dialogs"); gtk_window_set_resizable(dialogWindow, 0); vbox := gtk_box_new(GtkVertical, 8); gtk_widget_set_margin_start(vbox, 8); gtk_widget_set_margin_end(vbox, 8); gtk_widget_set_margin_top(vbox, 8); gtk_widget_set_margin_bottom(vbox, 8); gtk_window_set_child(dialogWindow, vbox); (* Standard message dialog *) hbox := gtk_box_new(GtkHorizontal, 8); gtk_box_append(vbox, hbox); button := gtk_button_new_with_mnemonic("_Message Dialog"); Connect2(button, "clicked", OnMessageDialog, NIL); gtk_box_append(hbox, button); gtk_box_append(vbox, gtk_separator_new(GtkHorizontal)); (* Interactive dialog *) hbox := gtk_box_new(GtkHorizontal, 8); gtk_box_append(vbox, hbox); vbox2 := gtk_box_new(GtkVertical, 0); button := gtk_button_new_with_mnemonic("_Interactive Dialog"); Connect2(button, "clicked", OnInteractiveDialog, NIL); gtk_box_append(hbox, vbox2); gtk_box_append(vbox2, button); table := gtk_grid_new(); gtk_grid_set_row_spacing(table, 4); gtk_grid_set_column_spacing(table, 4); gtk_box_append(hbox, table); label := gtk_label_new("Entry 1"); gtk_grid_attach(table, label, 0, 0, 1, 1); dialogEntry1 := gtk_entry_new(); gtk_grid_attach(table, dialogEntry1, 1, 0, 1, 1); label := gtk_label_new("Entry 2"); gtk_grid_attach(table, label, 0, 1, 1, 1); dialogEntry2 := gtk_entry_new(); gtk_grid_attach(table, dialogEntry2, 1, 1, 1, 1) END; IF gtk_widget_get_visible(dialogWindow) = 0 THEN gtk_widget_set_visible(dialogWindow, 1) ELSE gtk_window_destroy(dialogWindow); dialogWindow := NIL; dialogEntry1 := NIL; dialogEntry2 := NIL; dialogLocalEntry1 := NIL; dialogLocalEntry2 := NIL END; RETURN dialogWindow END DoDialog; BEGIN comboWindow := NIL; comboStringEntry := NIL; comboIdsDropDown := NIL; entryCompletionWindow := NIL; entryUndoWindow := NIL; dialogWindow := NIL; dialogEntry1 := NIL; dialogEntry2 := NIL; dialogLocalEntry1 := NIL; dialogLocalEntry2 := NIL; dialogCount := 0 END DemosChooser.