Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Dynamic Libraries (Linux)
#2
What's the reason for using a dynamic library rather than compiling with a header into the code?

It works just fine by removing the EXPORT tags on the file, making it a .h header, adding the flags to the compiler in QB64, and then building.
   

Code: (Select All)
'Declare Dynamic Library "listpick"
'    Function PickFromListUTF8& (title As String, prompt As String, items As String, ByVal startIndex As Long)
'    Function PickFromListUTF8_Text& (title As String, prompt As String, items As String, ByVal startIndex As Long, outText As String, ByVal outBytes As Long)
'End Declare

Declare CustomType Library "ListPick_GTK"
    Function PickFromListUTF8& (title As String, prompt As String, items As String, ByVal startIndex As Long)
    Function PickFromListUTF8_Text& (title As String, prompt As String, items As String, ByVal startIndex As Long, outText As String, ByVal outBytes As Long)
End Declare


' --- use ---
title$ = "Select item" + Chr$(0)
prompt$ = "Write for filter, Enter=OK, Esc=Cancel" + Chr$(0)

item:
Data "Alpha","Beta","Gamma","Delta","Etha","Theta","Omikron","Mi","Psi","Kocici","Kachni","Rozum","Zelenej","Linux","To je ale dilo"
Restore item
For f = 1 To 15
    Read i$
    items$ = items$ + i$ + Chr$(10)
Next f

items$ = items$ + Chr$(0)

out$ = Space$(2048) ' buffer, in which C write text
idx& = PickFromListUTF8_Text&(title$, prompt$, items$, 1, out$, Len(out$))

out$ = ZTrim$(out$)

Print "idx="; idx&, " text="; out$



Function ZTrim$ (s$)
    Dim p As Long
    p = InStr(s$, Chr$(0))
    If p > 0 Then ZTrim$ = Left$(s$, p - 1) Else ZTrim$ = s$
End Function

Code: (Select All)
// listpick_gtk.c  (GTK3, UTF-8)
// build (bash/zsh):
//   gcc -O2 -fPIC -shared -o liblistpick.so listpick_gtk.c $(pkg-config --cflags --libs gtk+-3.0)
// build (fish):
//   gcc -O2 -fPIC -shared -o liblistpick.so listpick_gtk.c (pkg-config --cflags --libs gtk+-3.0)

#include <gtk/gtk.h>
#include <string.h>

typedef struct {
    GtkWidget *dialog;
    GtkWidget *entry;
    GtkWidget *list;     // GtkListBox
    GPtrArray *rows;     // index(orig) -> GtkListBoxRow*
    int bestOrig;        // preferovaný origin index
} Picker;

static int gtk_ready = 0;

static gboolean row_is_effectively_visible(GtkWidget *w) {
    // u GtkListBox filtrování typicky schovává řádky přes child_visible, ne přes visible
    return gtk_widget_get_child_visible(w);
}

static gboolean contains_nocase_utf8(const char *hay, const char *needle) {
    if (!needle || !*needle) return TRUE;
    if (!hay) return FALSE;

    char *h = g_utf8_casefold(hay, -1);
    char *n = g_utf8_casefold(needle, -1);
    gboolean ok = (g_strstr_len(h, -1, n) != NULL);
    g_free(h);
    g_free(n);
    return ok;
}

static gboolean row_filter(GtkListBoxRow *row, gpointer user_data) {
    Picker *p = (Picker *)user_data;
    const char *needle = gtk_entry_get_text(GTK_ENTRY(p->entry));
    if (!needle || !*needle) return TRUE;

    GtkWidget *child = gtk_bin_get_child(GTK_BIN(row)); // GtkLabel
    const char *text = gtk_label_get_text(GTK_LABEL(child));
    return contains_nocase_utf8(text, needle);
}

static void ensure_selection(Picker *p) {
    GtkListBox *box = GTK_LIST_BOX(p->list);

    GtkListBoxRow *sel = gtk_list_box_get_selected_row(box);
    if (sel && row_is_effectively_visible(GTK_WIDGET(sel))) return;

    // 1) zkus bestOrig (naposledy vybraná položka), pokud je viditelná ve filtru
    if (p->bestOrig >= 0 && p->bestOrig < (int)p->rows->len) {
        GtkListBoxRow *want = (GtkListBoxRow *)g_ptr_array_index(p->rows, p->bestOrig);
        if (want && row_is_effectively_visible(GTK_WIDGET(want))) {
            gtk_list_box_select_row(box, want);
            return;
        }
    }

    // 2) první viditelný řádek
    GList *children = gtk_container_get_children(GTK_CONTAINER(box));
    for (GList *l = children; l; l = l->next) {
        GtkWidget *w = GTK_WIDGET(l->data);
        if (row_is_effectively_visible(w)) {
            gtk_list_box_select_row(box, GTK_LIST_BOX_ROW(w));
            break;
        }
    }
    g_list_free(children);
}

static void on_entry_changed(GtkEditable *editable, gpointer user_data) {
    (void)editable;
    Picker *p = (Picker *)user_data;

    gtk_list_box_invalidate_filter(GTK_LIST_BOX(p->list));
    while (gtk_events_pending()) gtk_main_iteration(); // ať se child_visible přepočte hned

    ensure_selection(p);
}

static void on_row_selected(GtkListBox *box, GtkListBoxRow *row, gpointer user_data) {
    (void)box;
    Picker *p = (Picker *)user_data;
    if (!row) return;
    int orig = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(row), "orig"));
    p->bestOrig = orig;
}

static void on_row_activated(GtkListBox *box, GtkListBoxRow *row, gpointer user_data) {
    (void)box; (void)row;
    Picker *p = (Picker *)user_data;
    gtk_dialog_response(GTK_DIALOG(p->dialog), GTK_RESPONSE_OK);
}

static gboolean on_key_press(GtkWidget *w, GdkEventKey *e, gpointer user_data) {
    Picker *p = (Picker *)user_data;

    if (e->keyval == GDK_KEY_Escape) {
        gtk_dialog_response(GTK_DIALOG(p->dialog), GTK_RESPONSE_CANCEL);
        return TRUE;
    }
    if (e->keyval == GDK_KEY_Return || e->keyval == GDK_KEY_KP_Enter) {
        // před OK ještě pro jistotu dorovnej selection podle filtru
        ensure_selection(p);
        gtk_dialog_response(GTK_DIALOG(p->dialog), GTK_RESPONSE_OK);
        return TRUE;
    }
    if (w == p->entry && (e->keyval == GDK_KEY_Down || e->keyval == GDK_KEY_Up)) {
        gtk_widget_grab_focus(p->list);
        return FALSE;
    }
    return FALSE;
}

static void copy_out(char *out, int outBytes, const char *src) {
    if (!out || outBytes <= 0) return;
    out[0] = 0;
    if (!src) return;
    g_strlcpy(out, src, (gsize)outBytes);
}

static int pick_run_utf8(const char *title, const char *prompt, const char *items, int startIndex,
                         char *out, int outBytes) {
    if (!gtk_ready) {
        int argc = 0;
        char **argv = NULL;
        gtk_ready = gtk_init_check(&argc, &argv) ? 1 : 0;
        if (!gtk_ready) {
            copy_out(out, outBytes, "");
            return -1;
        }
    }

    Picker p;
    memset(&p, 0, sizeof(p));
    p.bestOrig = (startIndex >= 0) ? startIndex : 0;
    p.rows = g_ptr_array_new();

    p.dialog = gtk_dialog_new_with_buttons(
        title ? title : "Select",
        NULL,
        GTK_DIALOG_MODAL,
        "_Cancel", GTK_RESPONSE_CANCEL,
        "_OK", GTK_RESPONSE_OK,
        NULL
    );
    gtk_window_set_default_size(GTK_WINDOW(p.dialog), 520, 380);

    GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(p.dialog));

    GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
    gtk_widget_set_hexpand(vbox, TRUE);
    gtk_widget_set_vexpand(vbox, TRUE);
    gtk_box_pack_start(GTK_BOX(content), vbox, TRUE, TRUE, 0);

    GtkWidget *lbl = gtk_label_new(prompt ? prompt : "");
    gtk_label_set_xalign(GTK_LABEL(lbl), 0.0f);
    gtk_label_set_line_wrap(GTK_LABEL(lbl), TRUE);
    gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0);

    p.entry = gtk_entry_new();
    gtk_box_pack_start(GTK_BOX(vbox), p.entry, FALSE, FALSE, 0);

    GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_widget_set_hexpand(sw, TRUE);
    gtk_widget_set_vexpand(sw, TRUE);
    gtk_widget_set_halign(sw, GTK_ALIGN_FILL);
    gtk_widget_set_valign(sw, GTK_ALIGN_FILL);
    gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);

    p.list = gtk_list_box_new();
    gtk_list_box_set_selection_mode(GTK_LIST_BOX(p.list), GTK_SELECTION_SINGLE);
    gtk_widget_set_hexpand(p.list, TRUE);
    gtk_widget_set_vexpand(p.list, TRUE);
    gtk_widget_set_halign(p.list, GTK_ALIGN_FILL);
    gtk_widget_set_valign(p.list, GTK_ALIGN_FILL);
    gtk_container_add(GTK_CONTAINER(sw), p.list);

    // naplň řádky (items jsou UTF-8, oddělené '\n')
    const char *s = items ? items : "";
    int orig = 0;

    while (*s) {
        const char *e = strchr(s, '\n');
        size_t len = e ? (size_t)(e - s) : strlen(s);

        while (len && s[len - 1] == '\r') len--;

        char *line = g_strndup(s, len);

        GtkWidget *row = gtk_list_box_row_new();
        GtkWidget *t = gtk_label_new(line);
        gtk_label_set_xalign(GTK_LABEL(t), 0.0f);
        gtk_label_set_ellipsize(GTK_LABEL(t), PANGO_ELLIPSIZE_END);
        gtk_container_add(GTK_CONTAINER(row), t);

        g_object_set_data(G_OBJECT(row), "orig", GINT_TO_POINTER(orig));
        gtk_list_box_insert(GTK_LIST_BOX(p.list), row, -1);

        g_ptr_array_add(p.rows, row);
        g_free(line);

        orig++;
        if (!e) break;
        s = e + 1;
    }

    // filtering
    gtk_list_box_set_filter_func(GTK_LIST_BOX(p.list), row_filter, &p, NULL);

    // signály
    g_signal_connect(p.entry, "changed", G_CALLBACK(on_entry_changed), &p);
    g_signal_connect(p.list, "row-selected", G_CALLBACK(on_row_selected), &p);
    g_signal_connect(p.list, "row-activated", G_CALLBACK(on_row_activated), &p);
    g_signal_connect(p.entry, "key-press-event", G_CALLBACK(on_key_press), &p);
    g_signal_connect(p.list,  "key-press-event", G_CALLBACK(on_key_press), &p);

    gtk_widget_show_all(p.list);
    gtk_list_box_invalidate_filter(GTK_LIST_BOX(p.list));
    gtk_widget_show_all(p.dialog);

    // start selection
    if (startIndex >= 0 && startIndex < (int)p.rows->len) {
        GtkListBoxRow *r = (GtkListBoxRow *)g_ptr_array_index(p.rows, startIndex);
        gtk_list_box_select_row(GTK_LIST_BOX(p.list), r);
    } else {
        ensure_selection(&p);
    }
    gtk_widget_grab_focus(p.entry);

    int resp = gtk_dialog_run(GTK_DIALOG(p.dialog));

    // při OK ještě jednou dorovnej selection podle filtru (klik na OK myší by jinak mohl vrátit starou selection)
    if (resp == GTK_RESPONSE_OK) {
        gtk_list_box_invalidate_filter(GTK_LIST_BOX(p.list));
        while (gtk_events_pending()) gtk_main_iteration();
        ensure_selection(&p);
    }

    int result = -1;
    if (resp == GTK_RESPONSE_OK) {
        GtkListBoxRow *sel = gtk_list_box_get_selected_row(GTK_LIST_BOX(p.list));
        if (sel && row_is_effectively_visible(GTK_WIDGET(sel))) {
            result = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sel), "orig"));
            GtkWidget *child = gtk_bin_get_child(GTK_BIN(sel));
            copy_out(out, outBytes, gtk_label_get_text(GTK_LABEL(child)));
        } else {
            copy_out(out, outBytes, "");
            result = -1;
        }
    } else {
        copy_out(out, outBytes, "");
        result = -1;
    }

    gtk_widget_destroy(p.dialog);
    while (gtk_events_pending()) gtk_main_iteration();

    g_ptr_array_free(p.rows, TRUE);
    return result;
}

// -------- exporty pro QB64PE (UTF-8) --------

int PickFromListUTF8(const char *titleUtf8, const char *promptUtf8,
                            const char *itemsUtf8, int startIndex) {
    return pick_run_utf8(titleUtf8, promptUtf8, itemsUtf8, startIndex, NULL, 0);
}

int PickFromListUTF8_Text(const char *titleUtf8, const char *promptUtf8,
                                 const char *itemsUtf8, int startIndex,
                                 char *outUtf8, int outBytes) {
    return pick_run_utf8(titleUtf8, promptUtf8, itemsUtf8, startIndex, outUtf8, outBytes);
}
The noticing will continue
Reply


Messages In This Thread
Dynamic Libraries (Linux) - by Petr - 12-15-2025, 11:53 AM
RE: Dynamic Libraries (Linux) - by SpriggsySpriggs - 12-15-2025, 12:22 PM
RE: Dynamic Libraries (Linux) - by luke - 12-15-2025, 12:33 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-15-2025, 04:32 PM
RE: Dynamic Libraries (Linux) - by SMcNeill - 12-15-2025, 06:05 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-15-2025, 06:20 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-15-2025, 06:56 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-15-2025, 07:19 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-16-2025, 10:51 AM
RE: Dynamic Libraries (Linux) - by Petr - 12-22-2025, 12:48 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-27-2025, 08:53 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-27-2025, 10:10 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-28-2025, 01:37 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-28-2025, 06:01 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-29-2025, 04:56 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-29-2025, 08:55 PM
RE: Dynamic Libraries (Linux) - by Petr - 12-29-2025, 09:52 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Dynamic Libraries (Windows) Petr 50 3,319 02-24-2026, 06:38 PM
Last Post: Petr

Forum Jump:


Users browsing this thread: 1 Guest(s)