{"id":20723899,"url":"https://github.com/ying32/liblcl","last_synced_at":"2025-04-05T05:04:19.642Z","repository":{"id":46590685,"uuid":"272850273","full_name":"ying32/liblcl","owner":"ying32","description":"A common cross-platform GUI library, the core uses Lazarus LCL.","archived":false,"fork":false,"pushed_at":"2024-12-25T10:22:30.000Z","size":9618,"stargazers_count":151,"open_issues_count":4,"forks_count":28,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-29T04:04:48.775Z","etag":null,"topics":["c","cpp","delphi","desktop-widget","go","golang","golang-library","govcl","gui","lcl","liblcl","rust","rust-library","vcl"],"latest_commit_sha":null,"homepage":"","language":"Pascal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ying32.png","metadata":{"files":{"readme":"README.en-US.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING.LGPL.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-17T01:31:55.000Z","updated_at":"2025-03-29T01:28:56.000Z","dependencies_parsed_at":"2023-12-27T12:24:37.995Z","dependency_job_id":"0aab0dac-718b-468b-9bc1-c4025aeeec8d","html_url":"https://github.com/ying32/liblcl","commit_stats":{"total_commits":231,"total_committers":1,"mean_commits":231.0,"dds":0.0,"last_synced_commit":"f18315a8eafc0326f5a4c3e38c1760819587491d"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ying32%2Fliblcl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ying32%2Fliblcl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ying32%2Fliblcl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ying32%2Fliblcl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ying32","download_url":"https://codeload.github.com/ying32/liblcl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289424,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","cpp","delphi","desktop-widget","go","golang","golang-library","govcl","gui","lcl","liblcl","rust","rust-library","vcl"],"created_at":"2024-11-17T04:10:17.398Z","updated_at":"2025-04-05T05:04:19.616Z","avatar_url":"https://github.com/ying32.png","language":"Pascal","funding_links":[],"categories":["Control packs"],"sub_categories":[],"readme":"\n* [中文](README.md)   \n* English   \n\n----\n**Check out the [dev](https://github.com/ying32/liblcl/tree/dev) branch for new features.**\n----\n\n# liblcl\n\nA common cross-platform GUI library, the core uses Lazarus LCL.\n\n----\n\n[Compilation guide](Compile.README.en-US.md)  \n\n----\n\n* Languages supported:  \n\n  * go: https://github.com/ying32/govcl  \n\n  * c/c++: [Tools/genBind/c](Tools/genBind/c)    \n\n----\n\nLanguage binding tool generator: [genBind](Tools/genBind), c/c++, rust and nim have been generated. Refer to the binding template files of these languages for details.\n\n----\n\n#### others  \n\n*All exported functions are in the standard c way.*  Use the `__stdcall` convention on Windows, and the `__cdecl` convention on other platforms.\n\n----\n\n##### Character Encoding   \n\nThe `utf-8` encoding is used by default on all platforms.\n\n----\n\n##### Default instanced class\n\n*No need to manually call create and release.*  \n\n```c\n\n// definition\nTApplication Application; // Application\nTScreen Screen;           // Screen\nTMouse  Mouse;            // Mouse\nTClipboard  Clipboard;    // Clipboard\nTPrinter Printer;         // Printer  \n\n// Get instance class pointer\nApplication = Application_Instance();\nScreen = Screen_Instance();\nMouse = Mouse_Instance();              \nClipboard = Clipboard_Instance();      \nPrinter = Printer_Instance();          \n```\n\n----\n\n##### Event callback\n\n*Event callbacks are divided into 3 types.*\n\n```c\n// x86: sizeof(uintptr_t) = 4\n// x64: sizeof(uintptr_t) = 8\n\n// Get the parameters in the event from the specified index and address\n#define getParamOf(index, ptr) \\\n (*((uintptr_t*)((uintptr_t)ptr + (uintptr_t)index*sizeof(uintptr_t))))\n```\n\n\n* Basic event callback  \n\n```c\ntypedef void(*ESYSCALL0)();  \ntypedef void(*ESYSCALL1)(intptr_t);  \ntypedef void(*ESYSCALL2)(intptr_t, uintptr_t);  \ntypedef void(*ESYSCALL3)(intptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL4)(intptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL5)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL6)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL7)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL8)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL9)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL10)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL11)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);  \ntypedef void(*ESYSCALL12)(intptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); \n \n\n// Callback function prototype\n// f:        Id or function pointer passed in through SetOnXXX \n// args:     Parameter array pointer, Get each member by getParamOf\n// argcount: Parameter array length\nstatic void* LCLAPI doEventCallbackProc(void* f, void* args, long argCount) {\n \n\t#define _A_(index) \\\n\t   getParamOf(index, args)\n\n    switch (argCount) {\n    case 0:  ((ESYSCALL0) (f))(); break;\n    case 1:  ((ESYSCALL1) (f))(_A_(0)); break;\n    case 2:  ((ESYSCALL2) (f))(_A_(0), _A_(1)); break;\n    case 3:  ((ESYSCALL3) (f))(_A_(0), _A_(1), _A_(2)); break;\n    case 4:  ((ESYSCALL4) (f))(_A_(0), _A_(1), _A_(2), _A_(2)); break;\n    case 5:  ((ESYSCALL5) (f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4)); break;\n    case 6:  ((ESYSCALL6) (f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5)); break;\n    case 7:  ((ESYSCALL7) (f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6)); break;\n    case 8:  ((ESYSCALL8) (f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6), _A_(7)); break;\n    case 9:  ((ESYSCALL9) (f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6), _A_(7), _A_(8)); break;\n    case 10: ((ESYSCALL10)(f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6), _A_(7), _A_(8), _A_(9)); break;\n    case 11: ((ESYSCALL11)(f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6), _A_(7), _A_(8), _A_(9), _A_(10)); break;\n    case 12: ((ESYSCALL12)(f))(_A_(0), _A_(1), _A_(2), _A_(3), _A_(4), _A_(5), _A_(6), _A_(7), _A_(8), _A_(9), _A_(10), _A_(11)); break;\n    }\n    // Always return NULL\n    return NULL;\n}\n\n// Set callback\nSetEventCallback(GET_CALLBACK(doEventCallbackProc));\n```\n\n* TForm message callback   \n```c\n// f: addr\n// msg: TMessage\nvoid* LCLAPI doMessageCallbackProc(void* f, void* msg) {\n   ((void(*)(void*))f)(msg);\n    return NULL;\n}\n\n// Set callback\nSetMessageCallback(GET_CALLBACK(doMessageCallbackProc));\n```\n\n* Thread synchronization callback  \n```c\n\nstatic TThreadProc threadSyncProc;\n\nvoid* LCLAPI doThreadSyncCallbackProc() {\n    if (threadSyncProc) {\n        ((TThreadProc)threadSyncProc)();\n        threadSyncProc = NULL;\n    }\n    return NULL;\n}\n\n// Set callback\nSetThreadSyncCallback(GET_CALLBACK(doThreadSyncCallbackProc));\n\n// Thread synchronization operation\nvoid ThreadSync(TThreadProc fn) {\n   \n#ifdef __GNUC__\n    pthread_mutex_lock(\u0026threadSyncMutex);\n#else\n    EnterCriticalSection(\u0026threadSyncMutex);\n#endif\n    threadSyncProc = fn;\n    Synchronize(FALSE);\n    threadSyncProc = NULL;\n#ifdef __GNUC__\n    pthread_mutex_unlock(\u0026threadSyncMutex);\n#else\n    LeaveCriticalSection(\u0026threadSyncMutex);\n#endif\n   \n}\n```\n\n##### \"set\" type operation  \n\n```c\n\n// Lazarus \"set\" addition, an index stored as a bit in val... with a subscript of 0\nTSet Include(TSet s, uint8_t val) {\n    return (TSet)(s | (1 \u003c\u003c val));\n}\n\n// \"set\" subtraction, index stored as a bit in val..., subscript 0\nTSet Exclude(TSet s, uint8_t val) {\n    return (TSet)(s \u0026 (~(1 \u003c\u003c val)));\n}\n\n// Judgment of \"set\" type, val indicates the number of digits, and the subscript is 0\nBOOL InSet(uint32_t s, uint8_t val) {\n    if ((s\u0026(1 \u003c\u003c val)) != 0) {\n        return TRUE;\n    }\n    return FALSE;\n}\n```\n\n----\n\n##### Initial liblcl example\n\n```c\n#define GET_CALLBACK(name) \\\n  (void*)\u0026name\n \nstatic void init_lib_lcl() {\n#ifdef __GNUC__\n    pthread_mutex_init(\u0026threadSyncMutex, NULL);\n#else\n    InitializeCriticalSection(\u0026threadSyncMutex);\n#endif\n\n    // Set the callback function of the event\n    SetEventCallback(GET_CALLBACK(doEventCallbackProc));\n    // Set message callback\n    SetMessageCallback(GET_CALLBACK(doMessageCallbackProc));\n    // Set thread synchronization callback\n    SetThreadSyncCallback(GET_CALLBACK(doThreadSyncCallbackProc));\n    // Initial instance class\n    Application = Application_Instance();\n    Screen = Screen_Instance();\n    Mouse = Mouse_Instance();            \n    Clipboard = Clipboard_Instance();    \n    Printer = Printer_Instance();        \n}\n\nstatic void un_init_lib_lcl() {\n#ifdef __GNUC__\n    pthread_mutex_destroy(\u0026threadSyncMutex);\n#else\n    DeleteCriticalSection(\u0026threadSyncMutex);\n#endif\n}\n```\n\n----\n\n### C language call liblcl example  \n\n```c\n\n#include \"liblcl.h\" \n\n \n#ifdef _WIN32\n\nchar *UTF8Decode(char* str) {\n    int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);\n    wchar_t* wCharBuffer = (wchar_t*)malloc(len * sizeof(wchar_t) + 1);\n    MultiByteToWideChar(CP_UTF8, 0, str, -1, wCharBuffer, len);\n\n    len = WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, 0, 0, 0, NULL);\n    char* aCharBuffer = (char*)malloc(len * sizeof(char) + 1);\n    WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, aCharBuffer, len, 0, NULL);\n    free((void*)wCharBuffer);\n\n    return aCharBuffer;\n}\n#endif\n\nvoid onButton1Click(TObject sender) {\n    ShowMessage(\"Hello world!\");\n}\n\nvoid onOnDropFiles(TObject sender, void* aFileNames, intptr_t len) {\n    printf(\"aFileNames: %p, len=%d\\n\", aFileNames, len);\n    intptr_t i;\n    for (i = 0; i \u003c len; i++) {\n        \n#ifdef _WIN32\n        char *filename = UTF8Decode(GetFPStringArrayMember(aFileNames, i));\n#else\n        char *filename = GetFPStringArrayMember(aFileNames, i);\n#endif\n        printf(\"file[%d]=%s\\n\", i+1, filename);\n#ifdef _WIN32\n        free((void*)filename);\n#endif\n    }\n}\n\nvoid onFormKeyDown(TObject sender, Char* key, TShiftState shift) {\n    printf(\"key=%d, shift=%d\\n\", *key, shift);\n    if (*key == vkReturn) {\n        ShowMessage(\"press Enter!\");\n    }\n\n    TShiftState s = Include(0, ssAlt);\n    if (InSet(s, ssAlt)) {\n        printf(\"ssAlt1\\n\");\n    }\n    s = Exclude(s, ssAlt);\n    if (!InSet(s, ssAlt)) {\n        printf(\"ssAlt2\\n\");\n    }\n}\n\nvoid onEditChange(TObject sender) {\n    printf(\"%s\\n\", Edit_GetText(sender));\n}\n\nint main()\n{\n#ifdef _WIN32\n    if (load_liblcl(\"liblcl.dll\")) {\n#endif\n#ifdef __linux__\n    if (load_liblcl(\"liblcl.so\")) {\n#endif\n#ifdef __APPLE__\n    if (load_liblcl(\"liblcl.dylib\")) {\n#endif\n        Application_SetMainFormOnTaskBar(Application, TRUE); \n        Application_SetTitle(Application, \"Hello LCL\"); \n        Application_Initialize(Application);\n\t\t\n        TForm form = Application_CreateForm(Application, FALSE);\n        Form_SetCaption(form, \"LCL Form\");\n        Form_SetPosition(form, poScreenCenter);\n        Form_SetAllowDropFiles(form, TRUE)\n        Form_SetOnDropFiles(form, onOnDropFiles);\n        Form_SetKeyPreview(form, TRUE);\n        Form_SetOnKeyDown(form, onFormKeyDown);\n        \n\n        // \n        //TMemoryStream mem = NewMemoryStream();\n        //MemoryStream_Write(mem, data, datalen);\n        //MemoryStream_SetPosition(mem, 0); \n        //ResFormLoadFromStream(mem, form);\n        //MemoryStream_Free(mem);\n        \n        // \n        //ResFormLoadFromFile(\"./Form1.gfm\", form);\n\n        TButton btn = Button_Create(form);\n        Button_SetParent(btn, form);\n        Button_SetOnClick(btn, onButton1Click);\n        Button_SetCaption(btn, \"button1\");\n        Button_SetLeft(btn, 100);\n        Button_SetTop(btn, 100);\n        \n        TEdit edit = Edit_Create(form);\n        Edit_SetParent(edit, form);\n        Edit_SetLeft(edit, 10);\n        Edit_SetTop(edit, 10);\n        Edit_SetOnChange(edit, onEditChange);\n\n        Application_Run(Application);\n\n        close_liblcl();\n    }\n    return 0;\n}\n```\n----\n\n### LICENSE  \n\n**Keep the same license agreement with Lazarus LCL components: [COPYING.modifiedLGPL](COPYING.modifiedLGPL.txt)**","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fying32%2Fliblcl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fying32%2Fliblcl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fying32%2Fliblcl/lists"}