{"id":17220877,"url":"https://github.com/kojix2/libui_paradise","last_synced_at":"2026-02-13T12:45:04.584Z","repository":{"id":42663536,"uuid":"405836495","full_name":"kojix2/libui_paradise","owner":"kojix2","description":"[Unofficial] libui_paradise repository. This repository automatically fetches RubyGem and creates pull requests with Github Actions. The copyright of the code belongs to shevy, not to kojix2.","archived":false,"fork":false,"pushed_at":"2025-01-17T03:03:31.000Z","size":291,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-25T15:34:43.230Z","etag":null,"topics":["libui","ruby"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/libui_paradise","language":"Ruby","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/kojix2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-09-13T04:50:48.000Z","updated_at":"2023-01-17T19:21:44.000Z","dependencies_parsed_at":"2025-03-25T15:32:44.456Z","dependency_job_id":"246643e1-8bd8-4f67-95c9-b65c8c5d4da6","html_url":"https://github.com/kojix2/libui_paradise","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kojix2%2Flibui_paradise","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kojix2%2Flibui_paradise/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kojix2%2Flibui_paradise/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kojix2%2Flibui_paradise/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kojix2","download_url":"https://codeload.github.com/kojix2/libui_paradise/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248472587,"owners_count":21109623,"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":["libui","ruby"],"created_at":"2024-10-15T03:53:30.411Z","updated_at":"2026-02-13T12:44:59.554Z","avatar_url":"https://github.com/kojix2.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://www.gobolinux.org/)\n[![forthebadge](https://forthebadge.com/images/badges/made-with-ruby.svg)](https://www.ruby-lang.org/en/)\n[![Gem Version](https://badge.fury.io/rb/libui_paradise.svg)](https://badge.fury.io/rb/libui_paradise)\n\nThis gem was \u003cb\u003elast updated\u003c/b\u003e on the \u003cspan style=\"color: darkblue; font-weight: bold\"\u003e05.12.2022\u003c/span\u003e (dd.mm.yyyy notation), at \u003cspan style=\"color: steelblue; font-weight: bold\"\u003e00:31:45\u003c/span\u003e o'clock.\n\n## The libui_paradise project\n\n\u003cimg src=\"https://i.imgur.com/hYf3sum.png\" style=\"margin: 0.75em; padding: 8px\"\u003e\n\n(This image has been partially auto-generated via **cfdg**, then modified\nby me via **gimp** and ImageMagick - the rounded borders were\ndone via ImageMagick. You can re-use this image if you would like to,\nincluding the colour-pattern, via a **CC BY 3.0** licence. See the following\nlink for that licence: https://creativecommons.org/licenses/by/3.0/. For\n**cfdg** itself, have a look at: https://www.contextfreeart.org/gallery/)\n\nThe **libui_paradise project** aims to enhance the official (upstream)\nruby-libui bindings a little bit.\n\nYou can find the upstream ruby-libui bindings, maintained by **kojix2**,\nhere:\n\nhttps://rubygems.org/gems/libui\n\n(Or visit the github page for ruby-libui here via this link:\nhttps://github.com/kojix2/LibUI )\n\n(Be wary of the name that I use on this page - the currently maintained gem is\ncalled **libui**; the older gem, which was called **libui-ruby**, is no longer\nmaintained since as of **2019**. In the document here I may call kojix2' gem\n**ruby-libui**, but the official name is simply **libui**, which refers to the\ngem mentioned above: https://rubygems.org/gems/libui - I understand that I\nam using a misnomer when I refer to this as **ruby-libui**, but it helps\nme remember, so ...)\n\nAside from this mentioned goal of **trying to enhance** the upstream ruby-bindings,\nthe **libui_paradise** project also attempts to demonstrate how we could **try to\nuse a DSL** to write less code in the long run; at the least less syntax.\n\nLess syntax is not automatically a win-win situation, but often it can\nbe very useful.\n\nExample for this:\n\n    _ = button('Hello world!') # for libui\n\nYou can use a similar variant in ruby-gtk3, for example:\n\n    _ = Gtk::Button.new('Hello world!')\n\nOr, if you want to use \"toplevel-methods\", like the above, identical to the\nfirst variant:\n\n    _ = button('Hello world!') # for ruby-gtk\n\nIn fact: if you notice the above three lines of code then there is indeed no\ndifference between which toolkit to use between the first variant and\nthe last variant. We could then, in theory, \"plug in\" different toolkits,\nbe it ruby-gtk, ruby-tk, ruby-libui and so forth. The **glimmer** project\nis doing this to some extent, as a general DSL wrapper over GUI-related\nfunctionality, including the www - see here: https://github.com/AndyObtiva/glimmer\n\nWe could even extend this to the www and generate the appropriate \ntags that way, by treating HTML tags as \"objects\". Note that this is\n\"in theory\"; in practice there are some shortcomings, or limitations,\nsuch as different toolkits not supporting the same widgets or\nfunctionality. The old ruby-qt toolkit, for example, required you to\nconnect slots to signals, due to qt requiring this. I do not know if\nthis is still the case or not, but back in the days this was \nnecessary and it complicated using ruby-qt a little bit.\n\nThe **libui_paradise gem** here is highly experimental at this stage\nand may not work for all use cases, or may have bugs - I am still\nlearning myself here. I want to see which API calls make the most sense\nin the long run, ideally even across different GUIs as well as the\nwww. (For those of you who have some experience with ruby-gtk this may\nseem familiar, as pointed out above - API elements such as **.set_text()**\nor **widget1.add(widget2)**; I kind of learned GUIs first via\n**ruby-gtk**, which evidently shaped my opinion on GUI layouts\nto some extent.)\n\nThe official ruby-libui project maintained by kojix2 comes with\n**13 examples** (August 2021) so far. I assume that more examples\nmay be added over the coming months and years depending on use\ncase, time availability, motivation and so forth. Have a look at\nthe code provided on the github page to understand what is going\non - in particular the **histogram** example is really nifty if\nyou want to play around with it **interactively**. It is probably the\nbest example in this regard, because it features interactive and\ndynamic use in a visual way - you can choose the colours, for\nexample. A spin-button allows for visual change too, but I think \ncolours are more impressive than simple up-and-down counters.\n\nOn windows this may look like so (via kotlin-libui):\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/histogram/histogram-windows7.png\" style=\"margin-left: 2em\"\u003e\n\nAlso check out kojix2' other examples in ruby-gtk - would be great\nif we could have the same in libui one day, but this also depends\non what upstream libui makes available, unless it is somehow\npossible to connect multiple shared libraries into libui; then\nwe could perhaps extend libui.\n\nI am trying to think about ways to simplify the code in these\nexamples as well, so that we can \"do more by writing less\". But as\nstated before: this is all **highly experimental** and subject\nto change. I am going via slow, tiny babysteps here! Constant\nwins the race in the long run, just remember the turtle versus\nthe rabbit. The rabbit always believed that he would win the\nrace ...\n\n**kojix2** pointed out that a half-baked or incomplete OOP design may\nnot make a lot of sense in regards to ruby-libui - we have to think a\nbit about **Fiddle::Pointer** which not everyone may have done before.\n\nOtherwise you may end up segfaulting everything all over the place\n(which I did run into already - but it is both scary and fun at the\nsame time!). Subclassing is also difficult to do properly - which\nfunctions should be called to create a \"proper\" subclass? May there\nbe problems as a consequence of trying this? I have no idea right\nnow. This is definitely more related to the C API of ruby than\n\"pure\", plain ruby as such. You kind of have to understand the \nunderlying C code to some extent.\n\nI do not really know C very well; **pointers** are way above my \nlevel of understanding, so **kojix2's** point is a fair one\nto make, since someone may have to maintain a growing code base -\nthis may well be the case here too, so 'defensive programming'\nis a viable strategy. There are examples where one has to work\naround ruby's GC too, for instance - this all makes this a little\nbit more complicated than plain, \"pure\" ruby code.\n\n**However had**, at the same I still want to **experiment** and see\nwhat may happen with the code in general - which pitfalls may happen\nor which things could be improved upon. I think the more people use\nlibui and ruby-libui, the better this may become in the long run.\nImagine we could almost create a full desktop system based on\nlibui! Even if the original scope never was aimed towards that. :D\n\nThis may then be fast enough for ruby-on-the-desktop, and simple\nenough to do that, too. Right now this has too many shortcomings;\nI miss CSS styling in particular. But, in theory, we could do\nthis. Anyone feels clever enough to use ruby as a desktop-UI\nlanguage via libui? I suppose it still requires some decent\nknowledge of C ...\n\nLots of different people could create widgets and add-ons when\nthis were possible ... but I digress.\n\n**Write a GUI once, run everywhere** (well ... at the least in\ntheory). This is an excellent idea, even if libui may not be\naround one day, that idea should be retained for other GUIs\nin the future.\n\nIt's quite difficult to get GTK and ruby-gtk to work on\n**windows** - I tried to compile it some weeks ago but I\nended up having \"missing symbols\" error messages afterwards.\nI managed to get the hello-world.c example working, but the\nmore complicated examples did not work for me.\n\nOn Linux this is much, much easier to do ... I literally just\ncompile GTK, after its dependencies are properly installed (glib,\npango, atk, and so forth), and then the ruby bindings maintained\nlargely by kou (and others), and ... it works! At the least\non linux.\n\n(I used to be able to run ruby-gtk2 on windows in the past,\na long time ago, using the provided binaries, but sadly upstream\nGTK developers no longer provide binaries as-is, and there are\nno binary bundles for ruby-gtk on windows anymore either. I\nassume it is possible if you know msys2, and the windows \nplatform, but I am no expert on either, so ...)\n\n**libui** is so much simpler to use on windows than GTK,\nthough - just do **gem install libui** and it'll work,\nas-is. Literally. That's it. I tried it on my windows\nlaptop and it **does** indeed work. That convinced me\nthat it makes sense to use libui and ruby-libui. The reason it\nworks is because the ruby-libui gem (just called **libui**)\nbundles the respective binaries, and it is quite small. This\nwould be much harder to do with ruby-gtk.\n\nNow I am trying to find more awesome examples to showcase\nwhat can be done. Who knows - perhaps even CSS may be supported\none day (perhaps only on linux though, which limits the \nbenefit of it; ruby-gtk3 does allow for CSS though). A\nfont example has also been provided, so we can upscale,\ndownscale, use different fonts, bold, in colours and so\non and so forth now.\n\nCheck out the colours in the file **basic_draw_text.rb**,\nas courtesy provided by kojix2. That way you can style\nthe content of a widget more easily - only the fiddle-protection\nagainst segfault parts is a bit strange, but that's a detail.\n\nThere currently is quite a bit of code to make this work;\nin the long run I plan to simplify this if possible. **The\nless code we have to write, the better** - as long as the\nend code is still **readable**.\n\nNote that the subclass situation may change eventually; see\nupstream kojix2 and related discussion for fiddle. For\nthe time being, though, I'll retain my old approach until\nI am sufficiently content with the project as-is. Right now\nlibui_paradise has way too much undocumented and untested\ncode and I still have not added all examples either (coloured\ntext, for instance, still has to be added; and more image-related\nexamples that are smaller). Stay tuned.\n\n## How to require the libui_paradise project\n\nIn order to **require the libui_paradise project**, use\nsomething like the following:\n\n    require 'libui_paradise'\n\nMore frequently if you look at the **examples/** subdirectory, the\nfollowing is used instead:\n\n    require 'libui_paradise/autoinclude'\n\nNote that this particular require call does a few things automatically,\nwhich may not always be what you may want to use. So, again - check\nout the official ruby-libui repository first, including the examples,\nbefore having a look at **libui_paradise**. This project here is a\ntinker-project, very unstable, subject to change - don't use it in\nproduction yet.\n\nIn my own projects I tend to use the above autoinclude variant\nmost of the time, because that way I can write less code (omit\na few lines).\n\n## How to require libui itself\n\nSimply do:\n\n    require 'libui'\n\nNote that the **libui_paradise gem** does so automatically if you require it.\nThe idea here is to simply use **libui_paradise** directly, while still allowing\nyou to use **libui** at the same time as well, should you prefer to do so.\n\n## How to get started with ruby-libui and the libui_paradise project?\n\nWell - as stated elsewhere, I first recommend to you that you look directly\nat ruby-libui provided by kojix2, in particular the examples that he \ndistributes in the gem. Work through the examples step-by-step, possibly\nstarting with the smallest example, see whether they work (they do,\nor should) and have a look at how things work - just to get an\noverview.\n\nHave a look at the code as well, in order to understand how it\nworks roughly; after some minutes or perhaps a very few hours of tinker-time\nyou should understand quite a bit already, if you already know ruby. Even\nmore so if you did work with GUIs before, including GUIs via a www-interface.\n\nThen you are recommended to look at the libui_paradise project and look to \nsee what has been added on top of what kojix2 provides. Look at the examples \nof the libui_paradise project as well (they are a bit simplified compared\nto the upstream examples; unfortunately a few of them currently do not \nwork), then consider using **libui_paradise/prototype/prototype.rb** in\nparticular. Copy it and adjust it to your project and use case, as-is. You\nmay want to remove the grid that is inside there and use a hbox or a vbox\ninstead, or a padded_hbox and padded_vbox. It's all quite simple actually\nonce you understand the basic API: windows, widgets, buttons, entries.\n\nFor example, a button can be added in this way to a vbox, if you use\nthe libui_paradise gem:\n\n    outer_vbox = padded_vbox # padded means that it will have some padding to the sides\n    button = ui_button('Hello world!') # You can drop the ui_ prefix if you'd like to\n    button.on_clicked {\n      puts 'Hello world!'\n    }\n    outer_vbox.minimal(button) # Use minimal space if possible. Or use .add().\n\nThat's it! Inside of the **.on_clicked {}** block you can run the ruby code\nthat you want to use. A button that is in a container (such as **vbox**) that\noutputs hello world when clicked. Can't get much simpler than that. \\o/\n\nYou can omit the **ui_** part above. I just use it to point out the difference;\nand because I'd otherwise may have to use \"button = button\" aka \"button = button()\"\nwhich may be confusing- Thus, using **ui_button()** appeared to make more\nsense in this regard.\n\n## How to add a margin in LibUI\n\nUse something like:\n\n    LibUI.window_set_margined(MAIN_WINDOW, 1)\n\n## Fiddle::Pointer and playing with pointers\n\nThe **ruby-libui bindings** make use of **Fiddle::Pointer** a lot -\nsee the file called **ffi.rb** in the ruby-libui gem (\"gem install libui\").\nIt's like **magic** to me - scary and awesome at the same time.\n\nAs a consequence the libui_paradise project has to 'handle' pointers\nas well, indirectly so, via whatever ruby-libui makes available.\n\nI decided that, at the least for the time being, we will add\n**ad-hoc code** straight to Fiddle::Pointer. This is not the\noptimal solution and I do not recommend doing so, even more so as \nwe modify Fiddle::Pointer directly which I don't think is a good\nidea; it may be better to have some proper data structures and\nperhaps **subclass** from Fiddle::Pointer instead, and then modify\nthat subclass instead. That may be better. But for the time being,\nthe code here will remain as it is, until we can come up with\nbetter ways to deal with the situation. For now **simplicity**\nrules.\n\nSome of the examples used require assigment to local variables\nto avoid the GC to kick in and cause the program to end. This\nis presently not very elegant - see a discussion between kojix2\nand kou to improve on this part. For the time being, though,\nsome of the examples require 'boilerplate' assignment to \nvariabless. Stay tuned for improvements in this regard; ideally\nwe can use libui without having to play with pointers ever.\n\n## Constraints of the libui_paradise gem\n\nThe libui_paradise gem comes with some **constraints**.\n\nFor example, many of the ad-hoc methods on **Fiddle::Pointer**\nwill only work after you called e. g. **ui_vbox** or a \nsimilar constructor where we registered which widgets are\ncreated (aka the **new_** methods that are available on\nthe **LibUI** 'namespace'). Only when this has happened\nwill that widget become registered in the main Hash.\n\nThat then means, logically, that if you use a method such as:\n\n    check_button = ui_check_button\n    check_button.is_active?\n\nThis will only work if that widget was created already prior\nto that \"method call\".\n\nWhat this means in practice is that it is best if you\n**create all the skeleton** (the **basic UI elements**) **before**\ncalling any other code, including on-clicked or on-toggle\nevents. Otherwise you may find nil values and don't\nknow why that is the case so. If this seems too complicated\nfor you, don't worry - the examples distributed via the\nlibui_paradise gem should work fine (except two buggy ones), so\nthe point of this subsection here is to keep your attention to\nthe fact that, as of right now, if you use libui_paradise, the\n**proper-order-of-elements is important**. Ideally create all\nthe widgets first, before you add additional functionality to them.\n\nThis is admittedly not a very elegant limitation right\nnow, and one day this restrictions may be removed or\nlifted - but for now, it is a limitation that requires\na tiny bit of discipline to work around, for the time being.\nSo, again - it is best to split up the skeleton UI from\nthe function.\n\n## How to use an 'Open File' button\n\nMost \u003cb\u003egraphical user interfaces\u003c/b\u003e have an \"open a local file\"\nfunctionality.\n\nI came up with the following solution for now:\n\n    outer_vbox = padded_vbox\n    button_open_file = button('Open file')\n    button_open_file.on_clicked {\n      filename = ui_open_file(window).to_s # This is the part that will open a local file.\n    }\n    outer_vbox \u003c\u003c button_open_file # Add the button to the outer-vbox.\n\nCalling the **.to_s** method on the Fiddle::Pointer yields the actual\nfilename. You can then add more code to deal with this.\n\n**window** above refers to the **main_window**. See the example\n**019_open_file_button_example.rb** for how this actually works.\n\nIn the future this may be even further simplified a little, as\nopening local files is a very common task in most GUIs. A\nsingle method probably should suffice for using such a\nspecialized button.\n\n## How to properly quit from a ruby-libui widget\n\nI found that:\n\n    LibUI.quit\n\nWorks best overall. And seems to suffice as well.\n\nThere are some other calls, such as destroy-control and similar\nactions, which are probably clean-up related - but by and large\n**LibUI.quit** seems to be the main part how to exit from a\nlibui-application.\n\nI document this here in the event that I forget it in a few\nmonths.\n\nIf you use the libui_paradise gem then you can use the\nfollowing method to use a quit button:\n\n    a_quit_button = ui_quit_button\n\nIf you want another textual description then you can do the\nfollowing:\n\n    a_quit_button = ui_quit_button(text: 'Open a local file') # That text description would be confusing though\n    a_quit_button = ui_quit_button(text: 'Exit the application') # Much better now! \\o/\n\nSo, as a reminder:\n\n    main_window = LibUI.window('Notepad', 500, 300, 1)\n    LibUI.close_properly(main_window)\n    # Or simpler:\n    close_properly(main_window)\n\nYou can also directly use a toplevel API such as:\n\n    LibUI.window_on_closing(main_window) {\n      LibUI.exit_from(main_window)\n    }\n\n## How to instantiate libui:\n\n    UI = LibUI\n    init = UI.init\n\nOr just:\n\n    LibUI.init\n\nSince as of 2022 I prefer the longer variant, e. g. **LibUI**init. The\nold UI constant (\"alias\") will be retained, but new code added to the\nlibui_paradise gem will not use **UI** - instead the slightly longer\n**LibUI** is used.\n  \n## Subclassing\n\nCurrently subclassing from LibUI elements does not work - I simply\nhave no idea how to \"subclass\" from a **Fiddle::Pointer**. Perhaps we\nhave to build up a data structure that behaves like **Fiddle::Pointer**\nbut also has methods that allow for a more direct 'OOP behaviour'. Has\nanyone tried this yet? I am scared to try considering I already got\nsegfaults everywhere ...\n\nEventually I may figure this out - or someone else with more knowledge\nwill make this available. We can probably 'fake' subclassing to\na pointer somehow ... after all ruby internally has to figure it\nout as well and probably did so already, on the C-level side via\nvarious functions.\n\n## Using scrolling-areas in LibUI\n\nThe following API can be used to create a new scrolling area:\n\n    LibUI.new_scrolling_area\n\nScrolling areas have horziontal and vertical scrollbars. The\namount that can be scrolled is determined by the area's\nsize, which is decided by the programmer (both when creating\nthe Area and by a call to SetSize). Only a portion of the\nArea is visible at any time; drawing and mouse events are\nautomatically adjusted to match what portion is visible,\nso you do not have to worry about scrolling in your\nevent handlers.\n\nThe method LibUI.new_scrolling_area() accepts three arguments.\nThe second and third are width and height, respectively\n(as **integers**).\n\nThe first argument is the area handle. It has the following\npointer types (struct):\n\n    .Draw\n    .MouseEvent\n    .MouseCrossed\n    .DragBroken\n    .KeyEvent\n\nThe handlerDraw() function in C looks like this:\n\n    static void handlerDraw(uiAreaHandler *a, uiArea *area, uiAreaDrawParams *p)\n    {\n\t    uiDrawTextLayout *textLayout;\n\t    uiFontDescriptor defaultFont;\n\t    uiDrawTextLayoutParams params;\n\n\t    params.String = attrstr;\n\t    uiFontButtonFont(fontButton, \u0026defaultFont);\n\t    params.DefaultFont = \u0026defaultFont;\n\t    params.Width = p-\u003eAreaWidth;\n\t    params.Align = (uiDrawTextAlign) uiComboboxSelected(alignment);\n\t    textLayout = uiDrawNewTextLayout(\u0026params);\n\t    uiDrawText(p-\u003eContext, textLayout, 0, 0);\n\t    uiDrawFreeTextLayout(textLayout);\n\t    uiFreeFontButtonFont(\u0026defaultFont);\n    }\n\nThe scrollable area may look like this:\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/hello/hello-windows.png\"\u003e\n\n## Quickly adding text to a widget\n\nYou can use something like this if you use the libui_paradise gem:\n\n    outer_vbox = ui_vbox\n    outer_vbox.text(\n      'This widget can be used to do xyz.'\n    )\n\nHere .text() just means to add a text onto the vertical box.\n\nAgain - this modifies **Fiddle::Pointer**, so be wary when using\nit. The second argument is the default one for use in a\nlabel / ui_text widget.\n\n## Working with combo-boxes\n\nTo create a combo-box in vanilla libui, do this:\n\n    alignment = LibUI.new_combobox\n    LibUI.combobox_append(alignment, 'Left')\n    LibUI.combobox_append(alignment, 'Center')\n    LibUI.combobox_append(alignment, 'Right')\n    LibUI.combobox_set_selected(alignment, 0)\n    LibUI.combobox_on_selected(alignment) { on_combobox_selected(@area) }\n\nThis is a bit cumbersome, so if you use libui_paradise this\ncan be simplified a bit.\n\nTo create a combo-box do:\n\n    combo_box = ui_combo_box\n\nYou can fill it with an array of entries **on creation-time** via:\n\n    combo_box = ui_combo_box([1,2,3,4]) # simply pass your Array here\n    combo_box = ui_combobox(%w( Left Center Right )) # three members of this Array\n\nThis will also focus (aka **select**) on the very first element\nwhen doing so by default, so you can get rid of 4-5 lines of \ncode. How fancy! \\o/\n\nIf you need to do so manually, and focus on another element,\nfor example, then you can use the following toplevel method:\n\n    LibUI.combobox_set_selected()\n\nFor instance:\n\n    LibUI.combobox_set_selected(combobox, 0) # The first one will be active too.\n  \nTo **query the currently selected value**, use:\n\n    LibUI.combobox_selected(pointer)\n\nThis is usually done via a **proc {}** object. See kojix2' examples.\n\nIn LibuiParadise a few custom methods were added, such as \n**.ui_sync_connect()**. This method was added to connect a\ncombo-box to a entry and automatically sync that entry whenever\nthe combo box is changed. See the example **007_combo_box_example.rb**\nfor how this works.\n\nOr, just as a one-liner example:\n\n    ui_sync_connect(@combo_box, @entry) # widget1, then widget2\n\nThis may not always work as you'd expect, so a third argument can\nbe passed (the array that populates the combo-box).\n\nSo:\n\n    ui_sync_connect(@combo_box, @entry, @array_here)\n\nThere are probably more elegant ways to solve this, but I only\nwanted to solve this quickly and move on.\n\nThe **source code** to the combo-box in libui, at the least\nfor UNIX/Linux, can be seen here:\n\nhttps://github.com/andlabs/libui/blob/master/unix/combobox.c \n\n## Error messages and ui_error_message\n\nIn LibUI respectively ruby-libui you can display error messages\nvia a popup window. These are also called **message-box** and\n**error message box**, respectively.\n\nThe API is something like this:\n\n    LibUI.msg_box(main_window, 'Information', 'You clicked the button')\n    LibUI.msg_box_error(main_window, 'Information', 'You clicked the button')\n\nThe first line shows a normal message box; the second line shows how to\nuse a message box specifically 'adapted' for displaying errors to the\nend user.\n\nLibuiParadise makes this available via **ui_msg_box** and **ui_msg_box_error**\nrespectively.\n\n## Libui Form\n\n**Form** is a container that takes labels for its contents. This is currently\njust a stub though - we may have to research this with better examples.\n\n## Libui Checkbox\n\nA simple checkbox example in **plain** ruby-libui follows:\n\n    checkbox = LibUI.checkbox('Checkbox')\n    checkbox_toggle_callback = proc { |pointer|\n      checked = LibUI.checkbox_checked(pointer) == 1\n      LibUI.checkbox_set_text(ptr, \"I am the checkbox (#{checked})\")\n    }\n\nThis may look like so on Linux:\n\n\u003cimg src=\"https://i.imgur.com/d7qWalZ.png\" style=\"margin-left: 2em; padding: 4px; border: 1px solid black;\"\u003e\n\nTo set such a checkbox to the checked-state (that is, as if the\nuser clicked on it), use:\n\n    checkbox.set_checked(1)\n\nTo query its state use:\n\n    checked = LibUI.checkbox_checked(pointer) == 1\n\nTo \u003cb\u003equery\u003c/b\u003e whether a checkbox is **active**, use code such as the\nfollowing:\n\n    checkbox.is_active?\n    checkbox.active?\n\nThis depends on the modifications to Fiddler::Pointer, so\nbe wary when you use this - there be dragons (perhaps). Most\nof these modifications are based on **.object_id**, which is\nregistered in a main, toplevel Hash in the \n**libui_paradise project**. Not very elegant, but simple, and\nit works (for the most part).\n\n## Adding a widget into another widget\n\nI chose the following **API** for this:\n\n    box1.add(box2, 1)\n\nNote that this is \"cheating\" a bit because the method **.add()** is defined\non **Fiddle::Pointer**. That's scary! Segfaults coming your way. But it\nalso seems to work to some extent. Which is amazing ... :-)\n\nIn ruby-gtk it is quite common to use **.add()**. While **.pack_start()**\nand **.pack_end()** are available in ruby-gtk as well, I think .add() is\nthe simpler name. We just **add a widget to another widget** - job done.\n\n(I may also use \u003c\u003c as alias to .add() and while \u003c\u003c is great, remember\nthat it can not easily be used all the time, e. g. box1 \u003c\u003c box2 \u003c\u003c \nbox3 versus box1.add(box2).add(box3) - the latter is a bit more\nresilient syntax-wise.)\n\nAs stated, **\u003c\u003c** was added as an alias to **.add()** but I am not yet sure\nif this is a very good idea. It's super-nifty to use \u003c\u003c everywhere, but it\nalso changes the syntax of the whole .rb file ... on the other hand, using\n\u003c\u003c is easier than .add() so ... I'll go with that as well. Remember\nthere is more than one way to do something in ruby - you need to \nselect the variant(s) that work best for you and possibly ignore the\nother variants.\n\nSince a while the above can be simplified a bit, as will be shown\nnext.\n\nRather than use:\n\n    box1.add(box2, 1)\n\nYou can now do this instead:\n\n    box1.maximal(box2)\n\nThis is a tiny bit longer, but you can omit the \", 1\" part, which is\nnice. The alternative is .minimal(), which defaults to:\n\n    add(second_widget, 0)\n\nSo the only difference between .maximal() and .minimal() will be\nwhether you pass 0 or 1 to the method. See the upstream libui\nAPI to understand the difference.\n\n## Libui Tabs\n\nThe notebook-tab may look like this:\n\n\u003cimg src=\"https://i.imgur.com/olWQAIJ.png\" style=\"margin-left: 2em\"\u003e\n\nA new tab can be created via:\n\n    tab = LibUI.new_tab\n\nTo populate the notebook-tab you can use .tab_append() such as\nshown next:\n\n    hbox1 = LibUI.new_horizontal_box\n    hbox2 = LibUI.new_horizontal_box\n    LibUI.tab_append(tab, 'Page 1', hbox1)\n    LibUI.tab_append(tab, 'Page 2', hbox2)\n    LibUI.tab_append(tab, 'Page 3', UI.new_horizontal_box)\n    LibUI.box_append(inner2, tab, 1)\n\n## Create a vertical box:\n\nUse code like this:\n\n    vbox = UI.new_vertical_box\n\nIf you use the libui_paradise gem, you can use this:\n\n    vbox = ui_vbox # or\n    vbox = padded_vbox\n\n## Adding a horizontal separator or a vertical separator\n\nThe method **UI.new_horizontal_separator** can be used to add (or rather\nfirst create) a horizontal separator.\n\nYou can then add it via .add() or \u003c\u003c if you use the libui_paradise\nproject. Alternatively you can use the toplevel method provided by\nruby-libui, since that is what the libui_paradise project is doing anyway.\n\nTo simplify this further, you can do something like this:\n\n    outer_vbox = ui_vbox # I call the most-outer vbox usually outer-vbox\n    outer_vbox.add_hsep\n    # outer_vbox.add_horizontal_separator # Or this variant if you prefer some verbosity instead.\n\nOr, perhaps better, use a padded vbox:\n\n    outer_vbox = padded_vbox # note that \"ui_\" is not used here\n    outer_vbox.add_hsep\n\nI needed this functionality to quickly add horizontal separators for some\nvisual cue in the **User Interface**. Using **.add_hsep** is very\nconvenient and fast to write/type. If you want more verbosity then remember\nthat you can always use the upstream API as-is.\n\nThe same applies to vertical separators, but I haven't used them yet\nactually. They do work, though.\n\nFor an interesting example, have a look at the following screenshot\nfrom example **031_separator_example.rb**.\n\n\u003cimg src=\"https://i.imgur.com/cXO6RF4.png\" style=\"margin: 1em; margin-left: 3em\"\u003e\n\nWhat is interesting is that all the horizontal lines come from using\na hsep (horizontal separator).\n\nThe syntax is different though:\n\n    vbox.minimal(hsep, 1)\n    vbox.minimal(hsep, 0)\n\nCarefully look at the area that surrounds the button in the middle.\n\nThe nearby area is padded, thanks to **vbox.minimal(hsep, 0)**. So\npassing **0** means this is quite elegant - you add padding between\ndifferent elements. But when you pass 1 then you get this strange\nbig block. I am not sure if this is how it should be, but if it is\nthen you can sort of use that as an additional visual cue. I am \nnot necessarily recommending this be done, but **if** you ever have\nsuch a use case then you can use it - which is another reason why\nI added this screenshot, so that I don't forget. :)\n\n## Padding elements in LibUI\n\nThe general API for setting padding to a container in LibUI\ngoes via:\n\n    LibUI.box_set_padded(box, 1) # The value is usually either 0 or 1.\n\nThe alignment value may be as follows:\n\n    0: Fill\n    1: Start\n    2: Center\n    3: End\n\nPositioning values may typically be:\n\n    0: Left\n    1: Top\n    2: Right\n\nHave a look at the example file \u003cb\u003elibui_paradise/examples/simple/007_control_gallery.rb\u003c/b\u003e\nto see how this could be used.\n\n## LibUI::FFI::DrawTextLayoutParams.malloc\n\nLibUI::FFI::DrawTextLayoutParams.malloc can be used to draw\ncoloured text.\n\n    params = UI::FFI::DrawTextLayoutParams.malloc\n    params.to_ptr.free = Fiddle::RUBY_FREE\n\n    params.Align = 'Left' # Use left alignment here.\n\n## Margins in LibUI\n\nThe **margin** property specifies if the window content should have a\nmargin or not. The default value is false, meaning that there will\nbe no margin.\n\nIn order to understand the difference, a visual image may be\nbest - the first image that is shown next shows **no margin**,\nwhereas the second image **shows** a margin.\n\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/11197111/16465935/804a30d4-3e41-11e6-8189-150e8cddc152.png\" style=\"margin-left: 2em\"\u003e\u003cbr\u003e\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/11197111/16465906/68304cfe-3e41-11e6-8ae0-3123205ee136.png\" style=\"margin-left: 2em\"\u003e\u003cbr\u003e\n\nNote that the API name is **margined** rather than **margin** - \ngot me a little while to get used to that name.\n\nThe API in Go is: __func (*Group) SetMargined__ respectively\n__func (g *Group) SetMargined(margined bool)__. When **true**\nthen the group has margins around the child widgets, as mentioned\nalready.\n\nThe **size** of the margins in use, is, unfortunately, determined\nautomatically by the OS - we currently (2021) do not have control\nover the size of the margin at hand via **libui**.\n\nCode examples for 'raw' **ruby-libui** are these:\n\n    UI.window_set_margined(MAIN_WINDOW, 1)\n    UI.group_set_margined(group, 1)\n\nBecause I prefer calling methods on objects, I added this instead:\n\n    MAIN_WINDOW.is_margined\n    MAIN_WINDOW.uses_a_margin # Or this variant.\n\nNote that we are here faking method-calls on a Fiddle::Pointer, but\nif we don't pay attention then it looks like **OOP**! If it walks\nlike a duck, quacks like a duck then ... it may be a\n**Fiddle::Pointer:Duck**!!!\n\nYou can use a toplevel margined window like this:\n\n    window = margined_window(:filename, 250, 150, 0)\n\n:filename (as Symbol) is an 'alias' - if given then\nthe filename will become the title of the window at\nhand. Only the raw filename will be used, so if you\nhave a file at **/tmp/foo/bar.rb** then the title\nof the window will be **bar.rb**.\n\n## Entry\n\nAn entry in libui may look like this:\n\n\u003cimg src=\"https://raw.githubusercontent.com/parro-it/libui-node/master/docs/media/UiEntry.png\" style=\"margin-left:1em\"\u003e\n\nSuch an entry can be set to be **read only** (readOnly: Boolean, aka true or false).\n\nThe upstream C code for libui-entry, for **unix/**, can be seen here:\n\nhttps://github.com/andlabs/libui/blob/master/unix/entry.c\n\n## Borderless windows and fullscreen windows\n\nA window that is **borderless: true** will not show any title or\noutside frame. This may be useful for games and what not.\n\nTo set the main window to full screen (occupy the whole monitor) do:\n\n   LibUI.window_set_fullscreen(main_window, 1)\n\n## Spinbutton / Spinbox\n\nYou can use the following API for a spinbox:\n\n    LibUI.new_spinbox\n\nTo create a new spinbox.\n\nTo specify the **min** and **max** range, pass them as parameters\non creation-time:\n\n    LibUI.new_spinbox(0, 100)\n\nIf you use the extensions found in the libui_paradise gem then\nyou can do this instead:\n\n    ui_spinbox\n    spinbox # this is the simplest variant\n    spinbox(0, 100)\n\nYou can also be more explicit and use a hash such as the following\nexample shows:\n\n    spinbutton = ui_spinbutton(start: 0, end: 100) # Start at 0, end at 100.\n\nYou should be able to set a new value of the spinbox via **.set_value**. Have\na look at the file at **libui_paradise/examples/rb 021_spinbutton_example.rb**\nto see how this works. \n\nRelevant methods in regard to the spinbox in libui are as follows:\n\n    LibUI.spinbox_on_changed()\n    LibUI.spinbox_set_value()\n    LibUI.spinbox_value() \n\nTo **set** a value use either of the following two methods:\n\n    spinbox.set_value(42)\n    spinbox.value = 42 # this works as well\n\nHere is a small image of how this looks:\n\n\u003cimg src=\"https://i.imgur.com/FxNTRse.png\" style=\"margin: 0.5em; margin-left: 2em\"\u003e\n\n## Create a text-view widget\n\nA text-view widget shows content, such as the content of a local file.\n\nIn libui the general API for this is:\n\n    LibUI.new_multiline_entry                      # this is a textview\n\n## Control Gallery\n\nHere is an image, from kotlin-libui, how this may look on windows:\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/controlgallery/controlgallery-windows7.png\" style=\"margin-left: 2em\"\u003e\n\n## LibUI.new_button() - how to work with buttons in LibUI\n\n\u003cb\u003eLibUI.new_button\u003c/b\u003e allows us to create a new button.\n\nExamples:\n\n    button1 = LibUI.new_button('Text')\n    button2 = LibUI.new_button('▶')\n\nNow, we need to \"tell\" this button what to do when it is\nclicked. This is done via Libui.button_on_clicked().\n\nExample:\n\n    LibUI.button_on_clicked(button) do\n      LibUI.msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')\n    end\n\n## Enabling / Disabling buttons in libui\n\nThis is, assumingly, already possible via:\n\n    libui/ui.h\n\n    Lines 105 to 107 in a0a9807\n     _UI_EXTERN int uiControlEnabled(uiControl *); \n     _UI_EXTERN void uiControlEnable(uiControl *); \n     _UI_EXTERN void uiControlDisable(uiControl *); \n\nIn ruby-libui this should be possible via:\n\n    LibUI.control_enable()\n    UI.control_enable()\n\n    LibUI.control_disable()\n    UI.control_disable()\n\nSee the example\n**libui_paradise/examples/complex/011_two_buttons_showing_how_to_enable_and_disable_them.rb**\nin how this works.\n\n## libui and ruby-libui internals\n\nThis is an incomplete subsection. I know almost nothing at all about\nC; kojix2 knows more, so I refer you to the homepage of ruby-libui\nrespectively.\n\nMost of the code for ruby-libui resides under **ffi.rb**. In August 2021\nthis file contains almost 1000 lines, including newlines. Still quite\nsome code. If you want to look at the raw content, have a look at\nthe following link for **ffi.rb**:\n\nhttps://raw.githubusercontent.com/kojix2/LibUI/main/lib/libui/ffi.rb\n\nThe two most important components there, as far as I understand it,\nare **try_extern** and **structs**.\n\nFor instance:\n\n    try_extern 'void uiOnShouldQuit(int (*f)(void *data), void *data)'\n\n    Control = struct [\n\nI assume that any support made available for ruby **must** have a\ncorresponding entry in **ffi.rb**. At the least this is how I\nunderstood it.\n\nIf it is not in **ffi.rb** then support for that was not (yet) added.\n\nIndividual enum entries can also be seen. For instance, for font-related\ndata the following attributes are in use: \n\n    AttributeTypeFamily         = 0\n    AttributeTypeSize           = 1\n    AttributeTypeWeight         = 2\n    AttributeTypeItalic         = 3\n    AttributeTypeStretch        = 4\n    AttributeTypeColor          = 5\n    AttributeTypeBackground     = 6\n    AttributeTypeUnderline      = 7\n    AttributeTypeUnderlineColor = 8\n    AttributeTypeFeatures       = 9\n\nYou can probably use the rubygems features of comparing old gem \nreleases with one another to see which support has been added to\nruby-libui over the past months or so. Most work was probably done\nin 2020 or even before that (there are some older ruby bindings\nto libui, but these work differently as kojix2 explained).\n\n## Limitations of/in LibUI\n\nLibUI is not perfect - it is missing many things that should work just fine\non the main operating systems. On top of that I'd love to support specific\nfeatures on a given operating system even if it is NOT cross-platform. But\nthis is not possible via LibUI.\n\nThe following subsection mentions a few constraints of LibUI in varying \ndegrees of complexity/importance:\n\n- No CSS support. I miss this. On ruby-gtk3 this is possible. In LibUI I can't.\n- Unable to set different fonts for an application other than using FontButton.\n\n## Using C structs via fiddle\n\nTo use C structs you may have to allocate memory.\n\nExample:\n\n    font_descriptor = UI::FFI::FontDescriptor.malloc\n    font_descriptor.to_ptr.free = Fiddle::RUBY_FREE\n\nThis is currently necessary. Hopefully Fiddle becomes\na bit more convenient to use in the future, so we don't\nhave to care about **malloc** when writing ruby anymore.\n\n## Structure of the project\n\nIn **September 2021** the libui_paradise project was re-arranged slightly. There\nis now a dedicated **libui_classes/** directory that \"simulates\" separate classes.\nFor example, libui_button now resides in **button.rb**. I use the same directory\nlayout in the **gtk_paradise** gem and I think it makes a lot of sense - at the\nleast I can quickly find the code that I may want to modify or extend. If I\nwant to extend buttons, then I modify **buttons.rb**. That's simple, right?\n\nAnother reason why the project was re-structured was so that we can use a\n**unified DSL** for the GUI elements in the long run.\n\nFor example, code such as the following:\n\n    _ = button\n    _.on_clicked {\n      puts 'Hello world!'\n    }\n\nShould work on ruby-gtk3, libui and all the other toolkits one day - even on\nthe www. But the different toolkits do not implement the same functionality.\nLibui only offers a reduced functionality, for instance. Thus, the DSL that\nwe may then use **can only support a subset of functionality**, whereas other\ntoolkits are more useful in this regard. This was an additional reason why files\nsuch as button.rb were created - it makes it easier to know which functionality\nhas to be changed in order for libui_paradise to enable such a unified\nDSL approach. This currently does not yet work fine in 2021, but one day it\nshould work just fine.\n\nNote that the older l**ibui_paradise gem** will be made available at the\nleast for three months (so until end of December 2021 at the least). It used\na different directory layout.\n\nYou may ask why the main module is called **LibuiParadise::Extensions**.\nWhy not modify LibUI directly? After all the gtk_paradise gem does the\nsame, by modifying **module Gtk** directly.\n\nThat is a good question, and the main reason for this is because I was\nnot sure whether I can actually get away with modifying the LibUI\nnamespace directly. Fiddle::Pointer still scares me, so I am experimenting.\n\nFor now I thought it best to create a separate module, that is then included\nand modified - see the **included hook** that is presently used. This seems\nto be simpler for the time being. I may plan to change a lot more one day,\nif I ever manage to find out how to simulate proper subclasses via\nFiddle::Pointer ... :) \n\n--------------------------------------------------------------------------------\n## SNIPPETS.md\n\nNext, the content of the file called **SNIPPETS.md** will be shown. Note\nthat this file will eventually be integreated into this file, and then\nsubsequently removed one day.\n\n\n\u003cpre\u003e\n# How to add a new main window:\n                                             # width, height, hasMenubar\n  main_window = UI.new_window('hello world', 300, 200, 1)\n\n  Source code:\n\n    https://raw.githubusercontent.com/andlabs/libui/master/unix/window.c\n\n# How to add a libui-widget to the main window / Designate a child widget:\n\n  UI.window_set_child(main_window, button)\n\n# Act on closing-event (on quit tag):\n\n  UI.window_on_closing(main_window) {\n    puts 'Bye Bye'\n    UI.control_destroy(main_window)\n    UI.quit\n    0\n  }\n  # Or simpler:\n  close_properly(main_window)\n\n# Add the window to the main UI:\n\n  UI.control_show(main_window)\n  main_window.show_the_controls # Or use this one here.\n\n\n# Add a checkbox (checkbox tag, checkbutton)\n\n  checkbox = UI.new_checkbox('Checkbox') # or ui_checkbox\n  checkbox_toggle_callback = proc { |pointer|\n    checked = UI.checkbox_checked(pointer) == 1\n    UI.window_set_title(MAIN_WINDOW, \"Checkbox is #{checked}\")\n    UI.checkbox_set_text(pointer, \"I am the checkbox (#{checked})\")\n    0\n  }\n  UI.checkbox_on_toggled(checkbox, checkbox_toggle_callback, nil)\n  UI.box_append(inner, checkbox, 0)\n\n\n# And the control:\n\n  UI.control_show(main_window)\n\n# Using a text-entry (ui entry tag):\n\n  text_entry = UI.new_entry\n  UI.entry_set_text(text_entry, 'Please enter your feelings')\n  UI.entry_on_changed(text_entry, text_changed_callback, nil)\n\n  # To set this on a \"multiline entry\", aka spanning several\n  # rows, do use:\n  UI.multiline_entry_set_text(entry1, 'Yo there')\n  ui_text_view # an alias used in libui_paradise\n\n  text1 = UI.entry_text(entry1) # Obtain text. You may have to call .to_s on it, to guarantee the String.\n  UI.multiline_entry_text # Obtain the text from a multiline entry.\n\n# Create a combobox (combo tag, combobox tag):\n\n  combobox_selected_callback = proc { |ptr|\n    puts \"New combobox selection: #{UI.combobox_selected(ptr)}\"\n  }\n  cbox = UI.new_combobox\n  UI.combobox_append(cbox, 'combobox Item 1')\n  UI.combobox_append(cbox, 'combobox Item 2')\n  UI.combobox_append(cbox, 'combobox Item 3')\n  UI.box_append(inner, cbox, 0)\n  UI.combobox_on_selected(cbox, combobox_selected_callback, nil)\n\n  # Or more concise:\n  combo_box = LibUI.combobox {\n    ['combobox Item 1', 'combobox Item 2', 'combobox Item 3']\n  }\n\n\n# Add content to an editable combox:\n\n  UI.append() # .append() adds the named item to the end of the EditableCombobox.\n\n\n\n\u003c/pre\u003e\n\n\n--------------------------------------------------------------------------------\n\n## Advantages and Disadvantages of the libui project\n\nIt would be unfair to only selectively name advantages but not talk about\ndisadvantages, so this subsection will show some limitations, trade-offs,\nconstraints and opportunities. This is not complete, but it may become\nsomewhat more complete over time. Stay tuned.\n\n(a) Advantages:\n\n- Works on windows out-of-the-box after you installed the libui-gem.\n- Is super-simple to use compared to other toolkits, including ruby-gtk.\n- Super-simple to build up a prototype for a GUI, buttons that work,\nspin-boxes, text-views and so forth. Faster than any other toolkit\nIMO.\n- Works cross-platform.\n\n(b) Disadvantage:\n\n- Limited ability to control the layout and size of widgets.\n- May look like utter crap ... :-)\n- Some functionality is missing, such as a scrolled-window for every widget.\n- No way to use different fonts in the same application and choosing a font\nis needlessly complicated. (This may not be completely correct, though -\nthe glimmer-dsl-libui has example that seem to work. But if you ask me\nright now in 2021 how this works via a standalone example then I can\nhappily tell you I have absolutely no idea. Which brings me to the\nnext problem...)\n- Lack of documentation. This part is REALLY annoying ...\n\nSome more disadvantages relate to Fiddle::Pointer. You kind of need to\nknow C fairly well as well as the GC in ruby, in order to understand\nwhat is going on. Since I don't, I hit a dead end, kind of.\n\nThis is so far in September 2021. Let's see what the future brings.\nPerhaps other toolkits will learn from libui and implement the good\nparts for **their own** widget set.\n\n## LibuiParadise.parse_this_config_file()\n\nThis method can be used to parse a .config file. This file should\ndescribe the main window, such as:\n\n     width:                                      1000\n     height:                                      150\n     title:                 Parse Config File Example\n\nI have been using this in gtk_paradise and I think it may be convenient\nif you create lots of small windows and widgets that you don't want\nto hardcode values for directly into the .rb file at hand.\n\nTo create a toplevel window from this use code such as the following:\n\n    use_this_config_file = '023_parse_config_file_example.config'\n    window = LibuiParadise.parse_this_config_file(use_this_config_file)\n\nIn fact, the example **023_parse_config_file_example.rb** shows how\nthis is used. The width of the main window will be 1000 and the\nheight only 150.\n\nThis functionality may be extended in the future. For example, we\ncould enable to automatically parse such a .config file if it \nexists, thus not even requiring that method call in the future.\n\nFor now, though, you have to explicitely use that method if you\nwant to instantiate such a window from a .config file. It will\nbe evaluated at a later time (past September 2021) how useful this\nreally is.\n\n## Width and Height of the main window\n\nDifferent computers / monitors have different display values\n(their monitor).\n\nI use a wide-screen LCD monitor, but I also have a smaller laptop,\nand I want **libui** to work there just as well.\n\nThe following API can be used to set the width and height of the\nmain window:\n\n    set_height()\n    set_width()\n\nYou can also use something like '95%' as input. In that case the\ndesired value will be calculated depending on the max-resolution\nof the current display. This presently only works on **linux**; if\nsomeone knows how to make this work on windows and Mac OSX let\nme know. (On these systems it will instead default to a hardcoded\nvalue of 1024 for width and 800 for height).\n\nThe following example shows how to use a percentage value:\n\n    set_height('80%')\n\n## Coloured Text\n\nAt this point I only show how this may look on Win7, re-using\nthe picture the **kotlin-libui developers** made available:\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/drawtext/drawtext-windows7.png\" style=\"margin-left: 2em\"\u003e\n\nDoesn't look that bad, right? May not be the prettiest GUI of all\ntimes, but it is functional - and simple.\n\n## DSLs for libui (in ruby)\n\nkojix2 pointed out that glimmer has support for libui; check it out\nhere:\n\nhttps://github.com/AndyObtiva/glimmer-dsl-libui\n\nlibui_paradise will support the same syntax (in the long run) as\nglimmer does, either directly, or via a module and a way to\nrequire it specifically. But stay tuned for this - right now as\nof late 2021 this is not yet guaranteed. (If anyone needs quick\nAPI changes, let me know and I'll change libui_paradise. Other\nthan that, the libui_paradise project is in a slow maintenance\nmode right now, so again, stay tuned. \\o/ )\n\n## Status of the libui_paradise project\n\nI am still, as of 2021, experimenting somewhat randomly. While I intend to\nimprove libui_paradise, it is a hobby project that is not as important\nas, say, the gtk_paradise project (which contains custom ruby-gtk\nrelated addons; ruby-gtk has a LOT more functionality than libui has,\njust look at the CSS-related aspects).\n\nI can not promise to work reliably on libui_paradise, but every now and\nthen, say every some weeks, I will try to add more code to it, in \nparticular examples and documentation. However had, keep in mind that\nthe project is not one of my most important projects, so it may not\nreceive as many updates as other projects; Andy is much more active\nrecently via glimmer-libui-dsl, so check out his project. See also\nthe following subsection, the \"Todo List\".\n\n## Todo List and Goals related to libui\n\nHere I will list some todo entries and related goals for libui or the\nlibui_paradise gem - if anyone finds out how to solve some of these\nlimitations, you are welcome to share!\n\nThis list may become outdated eventually, so assume that this has been\nvalid at one point in time, but may no longer be absolutely \"up to date\"\nanymore.\n\nHere goes:\n\n- Add more small, **standalone examples** showcasing how to use (and\ncombine) different functionality, in particular colourized text and use\nof (embedded) images if applicable. Ideally we should be able to\ncombine both freely, if possible. Ideally it should be a small functionality,\nto demonstrate **how** something can be done. Users can then expand from\nthis point for their own GUI sets.\n\n- Find out how to create \"proper\" subclasses to Fiddle::Pointer, simulating\na subclass to it.\n\n- Find out how halign and valign work in Libui-Grid. Somehow I can not easily reposition it ...\nor perhaps I have been able to, and just have not noticed this (may have to embed one\nwidget in another widget in order for this to come into effect)\n\n- Find out how to do ad-hoc calls on linux to gtk, so that we can use CSS.\nPerhaps some extension mechanism could be used, similar to how ffi works\nin general. Unfortunately this probably requires knowledge of C, so this\nis an obstacle for me. I should have learned C before ruby ... :P\n\n- Get more people to learn about libui and use them in their projects,\nin particular for simple applications. I think this is the most important\ngoal: we need more people to learn about libui and begin to use it. \nContribute to upstream as well. If we have a sufficiently large user\nbase then it should be easier to add new possibilities onto libui,\nwhich in turn will \"cascade\" downwards to all the other bindings \nto libui, be it in kotlin, python, ruby and so forth.\n\n## DateTime Widget\n\nLet's start with an image to show how the date-time picker may look\non windows:\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/datetime/datetime-windows7.png\" style=\"margin-left: 2em\"\u003e\n\nHere is another image, from Win10:\n\n\u003cimg src=\"https://i.imgur.com/Vkn4Vmg.jpg\" style=\"margin: 1em; margin-left: 2em\"\u003e\n\nThe basic API is this:\n\n    LibUI.date_time_picker_time\n\nOr rather:\n\n    date_time_picker = LibUI.new_date_time_picker\n    time = LibUI::FFI::TM.malloc\n    LibUI.date_time_picker_on_changed(date_time_picker) {\n      LibUI.date_time_picker_time(date_time_picker, time)\n    }\n\nModify this to suit your needs as-is.\n\nI tested this in **February 2022** on Linux. The next screenshot\nshows how this may look (on icewm):\n\n\u003cimg src=\"https://i.imgur.com/Jdbf6Jc.png\" style=\"margin: 1em\"\u003e\n\n## radio-buttons in LibUI\n\nThe syntax goes something like this:\n\n    rb = ui_radio_buttons\n    LibUI.radio_buttons_append(rb, 'Radio Button 1')\n    LibUI.radio_buttons_append(rb, 'Radio Button 2')\n    LibUI.radio_buttons_append(rb, 'Radio Button 3')\n    outer_vbox.minimal(rb) # add the radio-button control to the box.\n\nIn other words: you instantiate a new rb-radio-button 'pointer';\nand then you simply append the options onto it. The String above\nwill be the option at hand, e. g. 'Radio Button 1'.\n\nAs I am very lazy I don't want this boilerplate code, so the following\nvariant exists instead:\n\n    rb = ui_radio_buttons( ['Radio Button 1','Radio Button 2','Radio Button 3'] )\n    outer_vbox.minimal(rb) # add the radio-button control to the box.\n\nSo you can simply pass in an Array. This cuts down the number of\nlines necessary. \\o/\n\nHere is a screenshot to show how this looks (from\nexample **032_radio_button_example.rb**).\n\n\u003cimg src=\"https://i.imgur.com/aJOBQzn.png\" style=\"margin-left: 2em\"\u003e\n\n## Password entries in LibUI\n\nIf you use the libui_paradise gem then you can create a new password entry\nin using any of the following variants:\n\n    entry = ui_password_entry\n    entry = password_entry\n\nFor \"raw\" libui, use this:\n\n    LibUI.new_password_entry\n\n## Tables in LibUI\n\nYou may be able to create a new table via:\n\n    table = LibUI.new_table\n    \n    model = LibUI.new_table_model(model_handler)\n\n    table_params = LibUI::FFI::TableParams.malloc\n    table_params = Fiddle::RUBY_FREE\n    table_params.Model = model\n    table_params.RowBackgroundColorModelColumn = -1\n    table = LibUI.new_table(table_params)\n\nThe table header is an array that contains the following attributes:\n\n    1. editable, bool type, the column is whether editable\n    2. textColor\n    3. title\n    4. type, specify value of button, image, imgtext, progress, checkbox, checkboxtext, color, text\n\nNote that this is incomplete; it's a bit complicated.\n\nIn the end, this is possible though:\n\n\u003cimg src=\"https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/table/table-windows7.png\" style=\"margin-left: 2em\"\u003e\n\n## Form example in LibuiParadise\n\nInspired by **glimmer-libui**, I ported the form example, into\n**027_form_example.rb**. Unfortunately it does not look \nas good as it does in **glimmer-libui**, and the code I use for\nit is too verbose right now.\n\nStill, if you are curious, this is how it looks on icewm\nin October 2021:\n\n\u003cimg src=\"https://i.imgur.com/FkU6aWd.png\" style=\"margin-left: 2em\"\u003e\n\nI may improve this eventually a bit, so that the alignment looks\nas good as it does on glimmer-dsl; the code of 27_form_example.rb\nmay also be cleaned up in the future (the glimmer-libui code \nlooks better). But for now this is how it is; Andy is very\nactively improving **glimmer-libui** right now.\n\n## Available widgets in libUI:\n\n    Button                 A button with a label\n    Checkbox               A checkbox with a label\n    Combobox               A simple combobox\n    ColorButton            A button for selecting a color\n    EditableCombobox       A combobox that can be edited.\n    Entry                  Text input, can be disabled.\n    FontButton             A button for selecting a font (Incomplete: Cannot set programmatically)\n    Form                   A container that takes labels for its contents\n    Grid                   A container that aligns widgets for window design\n    Group                  A container that provides a title for a set of items\n    Label                  Displays a single line of text\n    Menu                   Creates a single column of an application menu\n    MultilineEntry         An entry that allows multiple lines.\n    Time and Date Pickers  Allows choosing of a date and/or time.\n    ProgressBar            Displays a progress bar\n    RadioButton            A set of radio buttons\n    Separator              A simple vertical or horizontal separator\n    Slider                 A draggable slider for choosing a value in a range\n    Spinbox                A numerical input with a minimum and maximum range\n    Tab                    A set named tabs for placing items in\n    Window                 Contains any other widget, cannot be embedded in a container\n    VBox, HBox             A vertical or horizontal box for grouping items\n\nAvailable \"**new**\"-widgets in LibUI:\n\n    LibUI.new_area\n    LibUI.new_attributed_string\n    LibUI.new_group\n    LibUI.new_spinbox\n    LibUI.new_stretch_attribute\n    LibUI.new_background_attribute\n    LibUI.new_button                               # this is a simple button\n    LibUI.new_checkbox                             # this is a simple checkbox\n    LibUI.new_color_attribute\n    LibUI.new_color_button\n    LibUI.new_combobox                             # this is a combobox\n    LibUI.new_date_picker\n    LibUI.new_date_time_picker\n    LibUI.new_editable_combobox\n    LibUI.new_grid\n    LibUI.new_horizontal_box\n    LibUI.new_horizontal_separator                 # this is a simple horizontal separator\n    LibUI.new_image                                # this is a simple image\n    LibUI.new_italic_attribute                     # this is basically italic font-style\n    LibUI.new_label\n    LibUI.new_tab\n    LibUI.new_table                                # this is a simple table\n    LibUI.new_table_model\n    LibUI.new_table_value_image\n    LibUI.new_table_value_int\n    LibUI.new_table_value_color\n    LibUI.new_table_value_string\n    LibUI.new_time_picker\n    LibUI.new_menu                                 # this is a menu, appearing on the upper area\n    LibUI.new_multiline_entry                      # this is a textview\n    LibUI.new_non_wrapping_multiline_entry\n    LibUI.new_open_type_features\n    LibUI.new_password_entry\n    LibUI.new_underline_attribute\n    LibUI.new_entry\n    LibUI.new_progress_bar                         # this is a progress_bar\n    LibUI.new_underline_color_attribute\n    LibUI.new_family_attribute\n    LibUI.new_radio_buttons                        # this is for the radio button\n    LibUI.new_vertical_box\n    LibUI.new_features_attribute\n    LibUI.new_scrolling_area                       # this is a scrolling area\n    LibUI.new_vertical_separator\n    LibUI.new_font_button\n    LibUI.new_weight_attribute\n    LibUI.new_form                                 # this is a form\n    LibUI.new_size_attribute\n    LibUI.new_window\n    LibUI.new_slider                               # this is a slider\n\n## A search entry in LibUI\n\nThe API is:\n\n    LibUI.new_search_entry # this is a search entry\n\nHow does this look? The following image shows this:\n\n\u003cimg src=\"https://i.imgur.com/AueDc7l.png\" style=\"margin: 1em\"\u003e\n\n## Creating a new image in LibUI:\n\nUse the following API for this:\n\n    image = LibUI.new_image(width, height)\n\nYou can use external libraries to determine the width\nand height of an image, such as ChunkyPNG.\n\nExample for this:\n\n    canvas = ChunkyPNG::Canvas.from_io(this_file)\n    width = canvas.width\n    height = canvas.height\n\n## How to to build a menu-interface (menu tag):\n\n    help_menu = LibUI.new_menu('Help')\n    version_item = LibUI.menu_append_item(help_menu, 'Version')\n\n## Creating a new drawing area in LibUI\n\nThe following code should suffice:\n\n    handler             = LibUI::FFI::AreaHandler.malloc\n    handler.to_ptr.free = Fiddle::RUBY_FREE\n    histogram           = LibUI.new_area(handler)\n\n## Horizontal boxes\n\nA \u003cb\u003eHBox\u003c/b\u003e represents a \u003cb\u003ehorizontal box\u003c/b\u003e. The API for putting \nsomething into a hbox goes as follows, such as when you wish to put\na text-entry into the hbox:\n\n    LibUI.box_append(hbox1, text_entry, 1)\n\n## The slider widget\n\nIf you use the LibuiParadise gem then you can create and use a new slider\nlike this:\n\n    slider = ui_slider\n\n    # define our callback\n    slider_changed_callback = proc { |ptr|\n      puts \"New Slider value: #{UI.slider_value(ptr)}\"\n      0\n    }\n    LibUI.slider_on_changed(slider, slider_changed_callback) # last element is nil, but it seems we can omit it\n\nThis may look like so on Linux:\n\n\u003cimg src=\"https://i.imgur.com/GVKPMS7.png\" style=\"margin-left: 3em\"\u003e\n\n## Create a new tabbed notebook:\n\n   ui_tabs\n   ui_notebook\n\n## Creating a textview in LibUI:\n\nFirst, let's have a look how this may look:\n\n\u003cimg src=\"https://i.imgur.com/v287z2k.png\" style=\"margin: 1em\"\u003e\n\nNext, here is the toplevel API to create a new multiline entry:\n\n    LibUI.new_non_wrapping_multiline_entry\n\nIf you want to make it read only then you can use an API like this:\n\n    LibUI.multiline_entry_set_read_only(text, 1)\n\nIf you make use of the LibuiParadise gem then the above can be\nsimplified to:\n\n    text = multiline_entry('Hello world! This can be set to read only via .is_read_only().')\n    text.is_read_only # Now it is read-only.\n\n## Coloured box examples\n\nSince as of November 2021 you can use the libui_paradise gem to\ncreate coloured boxes:\n\n\u003cimg src=\"https://i.imgur.com/Ervg3vF.png\" style=\"margin: 0.5em; margin-left: 2em\"\u003e\n\nThe API for this goes like so:\n\n    LibuiParadise.draw_rectangle\n    LibuiParadise.draw_rectangle(50, 50, :steelblue) # width, height, html-colour to use\n\n## Attributed Strings in LibUI\n\nAn **AttributedString** is a string that contains information\nabout specific styles, such as text color, font, font size. It can be\ndrawn in a **UiArea element**.\n\nVarious ways to style such an attributed String is possible.\n\nFor instance, the text-weight part accepts these values\n\n    minimum\n    thin\n    ultraLight\n    light\n    book\n    normal\n    medium\n    semiBold\n    bold\n    ultraBold\n    heavy\n    ultraHeavy\n    maximum\n    # or  any number between minimum and maximum\n\nTo create an attributed String you can use the following API:\n\n    string = LibUI.new_attributed_string\n    attributes = LibUI.new_family_attribute(\"Courier New 30\") # Specify a certain font.\n    attribute = LibUI.new_color_attribute(0.75, 0.25, 0.5, 0.75) # And a certain colour.\n    LibUI.append_with_attribute(\"text color\", attribute, nil)\n\n## Using fonts in LibUI:\n\n    font_descriptor = UI::FFI::FontDescriptor.malloc\n    p 'Font family: '+font_descriptor.Family.to_s+\n      'Font size: '+font_descriptor.Size+\n      'Font weight: '+font_descriptor.Weight+\n      'Font italic: '+font_descriptor.Italic+\n      'Font stretch: '+font_descriptor.Stretch\n\n## How to run the main loop in libui\n\n    LibUI.main\n\n## Examples distributed in the libui_paradise gem\n\nIn February 2022 the examples directory was re-arranged. There are now two\ndifferent directories, called simple/ and complex/.\n\nFiles in the simple/ directory may only use code that is made available\nvia kojix2' libui bindings.\n\nFiles in the complex/ directory may tap into code made available by the\nlibui_paradise gem.\n\nThis re-arrangement was done because some of the old examples were no\nlonger working, and it was messy to try to find out whether there was\na bug in the libui bindings, or whether I messed up. That way I can \nnow focus on the complex/ examples to showcase what libui_paradise\ncan do, whereas the simple/ directory will show how you can work with\n\"vanilla\" libui in general.\n\n## Setting the title, width and height of a widget\n\nThe libui_paradise gem comes with methods such as\n\u003cb\u003e.set_title()\u003c/b\u003e, \u003cb\u003e.set_width()\u003c/b\u003e and \n\u003cb\u003e.set_height()\u003c/b\u003e.\n\nThis is a bit cumbersome to use as you need at the least three lines\nof code normally, as well as the constants. So the following compound\nmethod was added in **February** of **2022**:\n\n    title_width_height()\n\nNow you can define title, width and height of your main window\nvia one method call. \\o/\n\n## Click-actions for buttons\n\nThis subsection just shows some code how main libui handles\nclick actions on buttons.\n\n    LibUI.button_on_clicked(button) {\n      LibUI.msg_box(main_window, 'Information', 'You clicked the button')\n      0\n    }\n\n## libui-ng\n\nIn **2022**, some developers contributed patches to **libui**. This is\n**work-in-progress**.\n\nSome API was added or modified, such as:\n\n    uiTableColumnWidth() API\n    uiTableColumnSetWidth() API\n    uiComboboxNumItems() API\n    uiOpenFolder() API\n    uiSliderHasToolTip() API\n    uiSliderSetHasToolTip() API\n    uiSliderSetRange() API\n    uiTableHeaderSortIndicator() API\n    uiTableHeaderSetSortIndicator() API\n    uiTableHeaderOnClicked() API\n    uiTableHeaderVisible() API\n    uiTableHeaderSetVisible() API\n    uiBoxNumChildren() API\n    uiFormNumChildren() API\n    uiComboboxInsertAt() API\n    uiComboboxDelete() API\n    uiComboboxClear() API\n    uiWindowResizeable() API\n    uiWindowSetResizeable() API\n    uiDrawPathEnded() API\n    uiFreeFontDescriptor() API\n    uiLoadControlFont() API\n\nNot all of this is supported in kojix2' libui as of\nyet, but it may be supported eventually. \n\n## Links related to libui or libui-based projects\n\nThis subsection may contain a few links, in the event that other\npeople want to see useful entries.\n\nI will try to explain what is to be seen by these various pages.\n\n(1) https://wiki.call-cc.org/eggref/4/libui\n\nThis is using chicken-egg scheme for bindings to libui. I like the\nsimplicity and overview - it's really nice to read and use. I'd\nwish we would have this for ruby too. :)\n\nNote that the documentation is outdated as of 2021, though. A fate\nshared with a lot of documentation in general out there ...\n\n(2) https://pkg.go.dev/github.com/andlabs/ui\n\nThis is andlabs' documentation for libui, from the point of view of\n**Go**. It is probably the biggest, most complete documentation for\nlibui. While it is specific to Go, as it was written by the same\nauthor you can expect the documentation to be quite decent.\n\n(Note that some other bindings contain good documentation too,\nsuch as kotlin libui bindings and others.)\n\n(3) http://api.call-cc.org/4/doc/libui\n\nSimilar to the first one, but uses a different layout, which\nmay be helpful.\n\n## Grids in LibUI\n\nThe API for creating a new grid in libui is quite complex and\nhard to remember:\n\n    LibUI.grid_append(grid, entry1,      0, 0, 2, 1, 0, 0, 1, 0)\n    LibUI.grid_append(grid, text('Yo2'), 1, 0, 1, 1, 0, 0, 1, 0) # text() can be used if you use the libui_paradise gem\n\nWho can remember offhand what these values mean, though?\n\nThe upstream struct is this:\n\n    struct gridChild {\n\t    uiControl *c;\n\t    int left;\n\t    int top;\n\t    int xspan;\n\t    int yspan;\n\t    int hexpand;\n\t    uiAlign halign;\n\t    int vexpand;\n\t    uiAlign valign;\n\n\t    // have these here so they don't need to be reallocated each relayout\n\t    int finalx, finaly;\n\t    int finalwidth, finalheight;\n\t    int minwidth, minheight;\n    };\n\nThe documentation for Go has this signature:\n\n    func (g *Grid) Append(child Control, left, top int, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align)\n\nAppend adds the given control to the Grid, at the given coordinate. \n\nI assume that **uiControl c** refers to the widget that is to be embedded\ninto the grid, so the numbers that follow afterwards are the ones\nthat are important. Let's have a look at them, based on the above API\ncall, and only list these again, without the **()**:\n\n    # left, top, xspan, yspan, hexpand, halign, vexpand, valign\n    #  0,    0,    2,     1,      0,      0,       1,      0\n\nxspan and yspan refer to width; left and top refer to the position\nin the grid. hexpand and vexpand means whether the grid-cell will\nexpand horizontally or vertically. halign and valign, I think,\nare used to align the grid-cell horizontally and vertically, so you\ncan position them exactly in the middle.\n\nRecently (in \u003cb\u003eAugust 2021\u003c/b\u003e) I discovered that you can actually\nput a button-in-a-button. I don't know whether this is a bug or\na feature, but it is hilarious nonetheless.\n\nThe '\u003cb\u003eraw\u003c/b\u003e' code I used for this was the following:\n\n    LibUI.grid_append(grid, UI.new_button('3'),0,1,1,1,1,1,1,1)\n    LibUI.grid_append(grid, UI.new_button('4'),1,1,1,1,1,1,1,1)\n    LibUI.grid_append(grid, UI.new_button('5'),0,1,1,1,1,0,1,0)\n    LibUI.grid_append(grid, UI.new_button('6'),1,1,1,1,1,0,1,0)\n\nThis led to the following widget setup, as shown in this\nimage:\n\n\u003cimg src=\"https://i.imgur.com/6sWwWKh.png\" style=\"margin-left: 1em\"\u003e\n\nThe smaller buttons and the larger buttons can be clicked. They\nreside in the same grid-cell. As stated I do not know whether this is\na bug or a feature really, but this was quite hilarious to see.\nIn the event that I may forget this, I'll keep this here as a\n\u003cb\u003ereference\u003c/b\u003e.\n\nIf you want to pad the grid you can use the following method:\n\n    LibUI.grid_set_padded(grid, 25)\n\nYou can specify the alignment for an individual grid. For\ninstance, via \u003cb\u003euiAlignCenter\u003c/b\u003e you can align a grid\nto the center. (It seems as if uiAlignCenter is only\nused in a grid, though, so it seems as if we can not\nalign it elsewhere.)\n\nIn \u003cb\u003eAugust 2022\u003c/b\u003e I got fed up with the API, so I\nadded a new API to Libui-grid using a Hash.\n\nThe available keywords are, to keep it simple, the\nfollowing:\n\n    left\n    top\n    xspan\n    yspan\n    hexpand\n    halign\n    vexpand\n    valign\n\nThe file \u003cb\u003eexamples/complex/016_grid_example.rb\u003c/b\u003e shows\nthis new API, mixed with the old, original API.\n\nUsage example for the new API:\n\n    grid = libui_grid\n    grid.hash_grid(\n      text('Yo7'),\n      { left: 2, top: 3, xspan: 3, yspan: 3, hexpand: 0, halign: 0, vexpand: 0, valign: 0 }\n    )\n\nIn the closing days of \u003cb\u003eAugust 2022\u003c/b\u003e I went on\nto improve the above. Three new methods were \"added\"\nto grid (actually Fiddle::Pointer, but hopefully one\nday I can find out how to work on a grid directly\nin libui; right now I seem to only have to work with\nraw pointers, which confuses me).\n\nThese three methods are:\n\n    .left()\n    .right()\n    .new_line()\n\nSo, let's picture a grid. The very first cell is on the\ntop left, so we can use .left() to add a widget.\n\nFor instance:\n\n    grid.left(text('Hello world!'))\n\nThen we can add more elements, and for doing so we will\nuse .right() such as in:\n\n    grid.right(text('There is more to come!'))\n    grid.right(text('Still more'))\n\nOnce you want to move to the next row, you have to use:\n\n    grid.new_line()\n\nThis is still not ideal, but for the time being it\nhas to suffice. Note how much simpler it is compared\nto .attach() or .hash_grid().\n\nNot every value can be set right now; at a later time\nthat API may become more flexible. But for now this\nhas to suffice.\n\n## Progress Bars in LibUI\n\nHere an image how this may look:\n\n\u003cimg src=\"https://i.imgur.com/i1i4ppZ.png\" style=\"margin-left: 2em\"\u003e\n\nIf you use the LibuiParadise project then you can create a new\ninstance of a progress bar via \u003cb\u003ewrapper_new_progress_bar\u003c/b\u003e.\n\nExample:\n\n    progress_bar = wrapper_new_progress_bar\n\nTo then set a new value, use:\n\n    progress_bar.set_value()\n    progress_bar.set_value(50) # will be 50%\n\nYou can then query this value via:\n\n    @progress_bar.value? # This will return a String, though.\n\n## Entries in LibUI (ui_entry)\n\nThe official source for an \u003cb\u003eui_entry\u003c/b\u003e for UNIX (including Linux systems)\ncan be read here:\n\nhttps://github.com/libui-ng/libui-ng/blob/master/unix/entry.c\n\nPersonally I tend to \u003cb\u003ecreate a new entry element\u003c/b\u003e in this way:\n\n    entry = ui_entry\n\n    # or, if it shall be more GUI-agnostic, I do this:\n\n    entry1 = entry # where entry is entry() actually, and works for many GUI toolkits then\n\nTo \u003cb\u003eset new content\u003c/b\u003e to such an entry, do make use\nof the following method call:\n\n    entry.set_text('foobar') # Make sure it is a String; that seems to work better.\n\nTo \u003cb\u003equery\u003c/b\u003e the text content of such an entry, you can use the following API,\nif you use the libui_paradise gem:\n\n    entry.text?\n\nTo respond to events look at the **OnChanged** event.\n\nTo see a specific example where the user may input a password entry, have\na look at the following file that is distributed within the libui_paradise\ngem:\n\n    libui_paradise/examples/complex/012_password_entry_example.rb\n\nAn entry can be \u003cb\u003eset read only\u003c/b\u003e via:\n\n    entry.read_only # This has not been added into libui-paradise yet.\n\nTo \u003cb\u003erespond\u003c/b\u003e to \u003cb\u003eon-changed events\u003c/b\u003e, you can use:\n\n   LibUI.entry_on_changed()\n\nA more complete example of this:\n\n    text_changed_callback = proc { |ptr|\n      puts \"Current textbox data: '#{UI.entry_text(ptr)}'\"\n    }\n\n    text_entry = ui_entry\n    text_entry.set_text('Please enter a command')\n    text_entry.on_changed {\n      text_changed_callback\n    }\n\nThe Proc object has to be passed into the {} block variation.\n\nThe latter uses:\n\n    LibUI.entry_on_changed(text_entry, text_changed_callback, nil)\n\nIf you use the libui_paradise gem, and only need to obtain the\n(changed) text of an entry in LibUI, then you can use the\nfollowing simplified method call instead:\n\n    entry = ui_entry\n    entry.on_changed {\n      puts 'The text is now: '+entry.text?\n    }\n\n\n## Contact information and mandatory 2FA coming up in 2022\n\nIf your creative mind has ideas and specific suggestions to make this gem\nmore useful in general, feel free to drop me an email at any time, via:\n\n    shevy@inbox.lt\n\nBefore that email I used an email account at Google gmail, but in **2021** I\ndecided to slowly abandon gmail, for various reasons. In order to limit the\nexplanation here, allow me to just briefly state that I do not feel as if I\nwant to promote any Google service anymore when the user becomes the \nproduct (such as via data collection by upstream services). I feel this is\na hugely flawed business model.\n\nDo keep in mind that responding to emails may take some time, depending on\nthe amount of work I may have at that moment.\n\nIn \u003cb\u003e2022\u003c/b\u003e rubygems.org, or rather the corporate overlords who control the\nrubygems.org infrastructure these days, decided to make 2FA mandatory for every\ngem owner eventually: see\nhttps://blog.rubygems.org/2022/06/13/making-packages-more-secure.html\n\nMandatory 2FA will eventually be extended to all rubygems.org developers and\nmaintainers. As I can not use 2FA, for reasons I will skip explaining here,\nthis means that my projects will eventually be taken over by shopify (or,\ncorrespondingly, whoever effectively controls the rubygems.org ecosystem).\nAt that point, I no longer have any control what is done to my projects\nsince shopify (respectively those controlling the gems ecosystem) took away\ncontrol here. Not sure at which point ruby became corporate-controlled -\nthat was not the case several years ago.\n\nRuby also only allows 2FA users to participate on the issue tracker these\ndays:\n\n  https://bugs.ruby-lang.org/issues/18800\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkojix2%2Flibui_paradise","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkojix2%2Flibui_paradise","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkojix2%2Flibui_paradise/lists"}