Code Monkey home page Code Monkey logo

libui's Introduction

LibUI

test Gem Version glimmer-dsl-libui Pre-build

LibUI is a Ruby wrapper for libui and libui-ng.

๐Ÿš€ libui-ng - A cross-platform portable GUI library

๐Ÿ”˜ libui - Original version by andlabs.

Installation

gem install libui --pre   # libui-ng
  • The gem package includes the libui-ng shared library for Windows, Mac, and Linux.
    • Namely libui.dll, libui.dylib, or libui.so.
  • No dependencies required.
    • The libui gem uses the standard Ruby library Fiddle to call C functions.
Windows Mac Linux

Notes:

  • If you are using the 32-bit (x86) version of Ruby, you need to download the 32-bit (x86) native dll. See the Development section.
  • On Windows, libui may not work due to missing DLLs. In that case, you need to install Visual C++ Redistributable. See (#48)
  • Users with Raspberry Pi or other platforms will need to compile the C libui library. See the Development section.

Usage

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('hello world', 200, 100, 1)

button = UI.new_button('Button')

UI.button_on_clicked(button) do
  UI.msg_box(main_window, 'Information', 'You clicked the button')
end

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

UI.window_set_child(main_window, button)
UI.control_show(main_window)

UI.main
UI.quit

For more examples, see the examples directory.

General Rules

Compared to the original libui library written in C:

  • Method names use snake_case.
  • The last argument can be omitted if it's nil.
  • A block can be passed as a callback.
    • The block will be converted to a Proc object and added as the last argument.
    • The last argument can still be omitted when nil.

You can use the documentation for libui's Go bindings as a reference.

DSLs for LibUI

LibUI is not object-oriented because it is a thin Ruby wrapper (binding) for the procedural C libui library, mirroring its API structure.

To build actual applications, it is recommended to use a DSL for LibUI, as they enable writing object-oriented code the Ruby way (instead of procedural code the C way):

Working with fiddle pointers

require 'libui'
UI = LibUI
UI.init

To convert a pointer to a string:

label = UI.new_label("Ruby")
p pointer = UI.label_text(label) # #<Fiddle::Pointer>
p pointer.to_s # Ruby

If you need to use C structs, you can do the following:

font_button = UI.new_font_button

# Allocate memory
font_descriptor = UI::FFI::FontDescriptor.malloc
font_descriptor.to_ptr.free = Fiddle::RUBY_FREE
# font_descriptor = UI::FFI::FontDescriptor.malloc(Fiddle::RUBY_FREE) # fiddle 1.0.1 or higher

UI.font_button_on_changed(font_button) do
  UI.font_button_font(font_button, font_descriptor)
  p family:  font_descriptor.Family.to_s,
    size:    font_descriptor.Size,
    weight:  font_descriptor.Weight,
    italic:  font_descriptor.Italic,
    stretch: font_descriptor.Stretch
end
  • Callbacks
    • In Ruby/Fiddle, a C callback function is written as an object of Fiddle::Closure::BlockCaller or Fiddle::Closure. Be careful about Ruby's garbage collection - if the function object is collected, memory will be freed resulting in a segmentation violation when the callback is invoked.
# Assign to a local variable to prevent it from being collected by GC.
handler.MouseEvent   = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.DragBroken   = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})

Creating a Windows executable (.exe) with OCRA

OCRA (One-Click Ruby Application) builds Windows executables from Ruby source code.

To build an exe with Ocra, include 3 DLLs from the ruby_builtin_dlls folder:

ocra examples/control_gallery.rb        ^
  --dll ruby_builtin_dlls/libssp-0.dll  ^
  --dll ruby_builtin_dlls/libgmp-10.dll ^
  --dll ruby_builtin_dlls/libffi-7.dll  ^
  --gem-all=fiddle                      ^

Add additional options below if necessary:

  --window                              ^
  --add-all-core                        ^
  --chdir-first                         ^
  --icon assets\app.ico                 ^
  --verbose                             ^
  --output out\gallery.exe

Development

git clone https://github.com/kojix2/libui
cd libui
bundle install
bundle exec rake vendor:auto # vendor:build
bundle exec rake test

Pre-built shared libraries for libui-ng

Use the following rake tasks to download the shared library required for your platform:

rake -T

rake vendor:build[hash]          # Build libui-ng latest master [commit hash]
rake vendor:libui-ng:macos       # Download latest official pre-build for Mac to vendor directory
rake vendor:libui-ng:ubuntu_x64  # Download latest official pre-build for Ubuntu to vendor directory
rake vendor:macos_arm64          # Download pre-build for Mac to vendor directory
rake vendor:macos_x64            # Download pre-build for Mac to vendor directory
rake vendor:raspbian_aarch64     # Download pre-build for Raspbian to vendor directory
rake vendor:ubuntu_x64           # Download pre-build for Ubuntu to vendor directory
rake vendor:windows_x64          # Download pre-build for Windows to vendor directory
rake vendor:windows_x86          # Download pre-build for Windows to vendor directory

For example, if you are using a 32-bit (x86) version of Ruby on Windows, type vendor:windows_x86. These shared libraries are artifacts of the pre-build branch of kojix2/libui-ng. In that case, please let us know.

Using C libui compiled from source code

The following Rake task will compile libui-ng. meson or ninja is required.

bundle exec rake vendor:build

Alternatively, you can tell Ruby LibUI the location of shared libraries. Set the environment variable LIBUIDIR to specify the path to the shared library. (See #46). This is especially useful on platforms where the LibUI gem does not provide shared library, such as the ARM architecture (used in devices like Raspberry Pi).

Another simple approach is to replace the shared libraries in the gem vendor directory with the ones you have compiled.

Publishing gems

ls vendor             # check the vendor directory
rm -rf pkg            # remove previously built gems
rake build_platform   # build gems

# Check the contents of the gem
find pkg -name *.gem -exec sh -c "echo; echo \# {}; tar -O -f {} -x data.tar.gz | tar zt" \;

rake release_platform # publish gems

libui or libui-ng

  • From version 0.1.X, we plan to support only libui-ng/libui-ng.
  • Version 0.0.X only supports andlabs/libui.

Contributing

Would you like to contribute to LibUI?

  • Please feel free to send us your pull requests.
    • Small corrections, such as typo fixes, are appreciated.
  • Did you find any bugs? Submit them in the issues section!

Do you need commit rights?

  • If you need commit rights to my repository or want to get admin rights and take over the project, please feel free to contact @kojix2.
  • Many OSS projects become abandoned because only the founder has commit rights to the original repository.

Support libui-ng development

  • Contributing to the development of libui-ng is a contribution to the entire libui community, including Ruby's LibUI.
  • For example, it would be easier to release LibUI in Ruby if libui-ng could be built easily and official shared libraries could be distributed.

Acknowledgements

This project is inspired by libui-ruby.

While libui-ruby uses Ruby-FFI, this gem uses Fiddle.

License

MIT License.

libui's People

Contributors

andyobtiva avatar bolandross avatar gemmaro avatar kojix2 avatar nodai2hitc avatar rubyfeedback avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

libui's Issues

libui examples - see https://ring-lang.github.io/doc1.14/libui.html in particular for the "Text Drawing" example

Heya,

See this website: https://ring-lang.github.io/doc1.14/libui.html

(I did not know about the ring language, but for the purpose of this thread
I am only interested in the examples.)

The "Text Drawing" example shows how to use coloured text and what not.

I am trying to include this so that I can port my ruby-gtk3 widgets set into
libui, on windows. So having colours, and so forth would be great.

I tried to adapt it:

string = UI.new_attributed_string
attribute = UI.new_color_attribute(0.75, 0.25, 0.5, 0.75)
UI.attributed_string_append_unattributed('text color', attribute)

But I don't quite understand the API. I did however find out that I can
modify Fiddle::Pointer on an ad-hoc basis which is funny. I simply
added .add() and .set_text() ... always feeling that I am on the
risk of segfaulting EVERYTHING. And indeed I do! But I digress. :D

Would it be possible that ruby-LibUI could show a small Text Drawing
example? All examples may not have to be shown, I just wonder
about the API.

I understand that we first have to define the attribute and then somehow
tie this to the string, but I have no idea how to add this to the main
window then. So any example in this regard, even if only small, just
to show e. g. red coloured text, would be super-useful. Thanks for
reading!

Exe wont start (Fiddle::DLError) Windows 11 Notebook

I build an Exe using ocra for my Application

upgraded from Libui 0.0.12 to 0.0.13 (same issue)

I can start my Application without Problems on any Win 10 PC but on a single Windows 11 (upgraded Notebook from 10) i got this Error:

C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle.rb:61:in `initialize': No such file or directory (Fiddle::DLError)
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle.rb:61:in `new'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle.rb:61:in `dlopen'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle/import.rb:86:in `block in dlload'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle/import.rb:77:in `collect'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/fiddle/import.rb:77:in `dlload'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui/ffi.rb:12:in `<module:FFI>'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui/ffi.rb:7:in `<module:LibUI>'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui/ffi.rb:6:in `<top (required)>'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui.rb:21:in `require_relative'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui.rb:21:in `<module:LibUI>'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/libui-0.0.12/lib/libui.rb:6:in `<top (required)>'
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/gems/3.0.0/gems/glimmer-dsl-libui-0.2.23/lib/glimmer-dsl-libui.rb:33:in `<top (required)>'
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in `require'
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in `rescue in require'
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/src/lucsi.rb:3:in `<main>'
<internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- glimmer-dsl-libui (LoadError)
        from <internal:C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
        from C:/Users/Manuel/AppData/Local/Temp/ocr15B2.tmp/src/lucsi.rb:3:in `<main>'

I need to say on another Win 11 Notebook (Preinstalled) the Application run also without Problems.

Any Idea what i should do or check? Please tell me whatever further information you need, if you have a idea. Thanks

Strange behaviour - can libui respond to SIGINT?

Hey there kojix2,

Sorry for filling this issue tracker in the new year! :D

(I am just randomly testing libui again ... I sort of start with ruby-gtk when I wake up, fix
some old issues, then have more fun afterwards playing with libui hehe)

There is one thing that annoys me a bit.

When I start a .rb file with fiddle + libui, the widget works, it is shown, all works
fine. But I start it from the terminal (commandline, KDE konsole), and when when
I press ctrl+c I can normally quit. I usually do this because it is faster than
clicking with the mouse cursor.

But, libui or so seems to not respond to it. This is different to ruby-gtk.

In my custom ruby code I generally use a method such as this:

def register_sigint
  Signal.trap('SIGINT') { exit }
end; register_sigint

Then ctrl+c tends to work.

Is there a way to "assign" ctrl+c to cause a libui based .rb file
to also behave in the same way? Right now I can still use
ctrl+z for background sending, but I'd love to see ctrl+c also
works by default if that is possible. If not don't worry, just
ignore this issue request.

Fiddle::Pointer and OOP: can we modify Fiddle::Pointer? If not can we add something else that acts mostly like a pointer but also more advanced when necessary?

Hey there,

You wrote in the past that ruby-libui does not want to provide
incomplete solutions, e. g. the "half-baked" comment, in regards
to OOP. I understand that.

At the same time, I think there is a difference in philosophy at
work in regards to GUI-centric design.

For example, in pseudo code for libui:

hbox1  = UI.hbox # create a new horizontal box
entry1 = UI.entry('ATG') # create a new entry, and set the text to 'ATG')

Ok so far so fine. I am doing something similar in one of my gems,
just that rather than UI or LibUI I use directly Gtk.hbox and Gtk.entry,
so this is not a huge difference to libui.

But this step I don't like:

UI.box_append(hbox1, entry1, 1)

In ruby-gtk we may tend to use this instead:

hbox1.add(entry1)

To me, personally, I think using a method like this, aka .add(), or
.pack_start() or .pack_end(), is so much more convenient.

I even like doing something like this:

hbox1 << entry1

Using << is great.

I had a look at the "widgets" and .class always says Fiddle::Pointer.

So I assume we kind of work with the pointers as-such, and ruby as
DSL is mostly just a convenient wrapper over these pointers then.

I also assume - but may be wrong - that adding "functionality" to
such pointers is ... not trivial, since they don't provide a
platform for more actions - such as the .add() example.

Wouldn't it be cool if we could have some kind of meta data structure
that could be used to wrap over the raw libui pointers? These would
still act like Fiddle::Pointers, but we may add additional functionality,
in the sense that something like:

hbox1.add(entry1)

would then be possible.

Sadly I am a total noob when it comes to C/C++, so I have no idea how
difficult or simple that would be, and how much work. Mostly I am
not even concerned about the internals, I just want to be able to
have a more centric OOP-like DSL. Right now I have to use:

UI.do_something

and while that works, it's a bit tedious.

I'd rather prefer some layer similar to gtk, where we have widgets
and work on these widgets then. Like the box.add() example. So this
is the part that I think would be super-convenient.

I already wrote a module that extends the default LibUI, so I can
get away with things such as UI.entry() and what not, but I have
no idea what to do about Fiddle::Pointer. Can they be modified?
Are they unique? Is it dangerous when treating them like other
ruby objects? I kind of want to have something like box.add()
but I am scared - perhaps Fiddle::Pointer is restricted similar
to Numeric in ruby which isn't quite "full" OOP either.

Last but not least: I think half-hearted OOP may still be better
than no OOP, if it is centered around the DSL part - aka to
treat what matz once said about ruby in this ancient interview:

https://www.artima.com/articles/the-philosophy-of-ruby

So perhaps we can have some kind of meta-OOP-layer, even if it
is not a "full" OOP layer like in gtk or qt. :)

PS: The various procs are also a bit tedious. I much prefer
working with methods. Of course the proc can just be a wrapper
over a method call, so this can be solved, but I found it
more convenient if I don't use any procs. But that is another
issue; for here I am more interested in a box.add(widget)
DSL.

PSS: I understand that libui's philosophy will remain to be simple
which is fine. I'd just think simplicity may also exist in simpler
APIs/DSLs. :)

Editable Table Example

Hi,

Thank you for providing such a useful Ruby gem and for adding Glimmer DSL for LibUI to the list of supported LibUI DSLs.

I wanted to note that I just released initial support for the table control, supporting only text_columns for the time being.

Your implementation of examples/basic_table.rb was a very helpful reference for my DSL reimplementation.

Glimmer DSL for LibUI examples/basic_table.rb

require 'glimmer-dsl-libui'

include Glimmer

data = [
  %w[cat meow],
  %w[dog woof],
  %w[chicken cock-a-doodle-doo],
  %w[hourse neigh],
  %w[cow moo]
]

window('Animal sounds', 300, 200) {
  horizontal_box {
    table {
      text_column('Animal')
      text_column('Description')

      cell_rows data
    }
  }
  
  on_closing do
    puts 'Bye Bye'
  end
}.show

I aim to support different types of table columns eventually like image_column, and I am able to pursue this effort on my own.

That said, I also plan to support editable tables, and this is where I need help. I was wondering if you could provide examples/editable_table.rb example similar to examples/basic_table.rb that simply enables table editing.

What I understand so far on my own is that these two lines of code need to have their last argument changed from -1 to -2 to enable editing (I tried it successfully):

UI.table_append_text_column(table, 'Animal', 0, -1)
UI.table_append_text_column(table, 'Description', 1, -1)

becomes

UI.table_append_text_column(table, 'Animal', 0, -2)
UI.table_append_text_column(table, 'Description', 1, -2)

Next, to persist changes of edited values, this block of code needs to do extra work:

model_handler.SetCellValue = rbcallback(0, [0]) {}

That is exactly where I need your insight. I do not know Fiddle at all (a big reason why I highly appreciate your Ruby gem) so I do not understand how to hook into libui correctly to receive updated cell values and save them into the data array (e.g. via some code like data[row][column] = value)

If you could help me by producing the suggested examples/editable_table.rb example, I would be very grateful!

Best regards,

Andy

Windows 10 x64 issue with Fiddle and libui

I tried libui on Windows 10 x64 after installing Ruby 3.0.2 x64 via Ruby Windows Installer (and running gem install glimmer-dsl-libui to install gem + dependencies) and I keep getting this error upon loading libui:

$ ruby -r glimmer-dsl-libui -e "require 'examples/basic_window'"
e:/Ruby30-x64/lib/ruby/3.0.0/fiddle.rb:49:in `initialize': No such
file or directory (Fiddle::DLError)
        from e:/Ruby30-x64/lib/ruby/3.0.0/fiddle.rb:49:in `new'
        from e:/Ruby30-x64/lib/ruby/3.0.0/fiddle.rb:49:in `dlopen'
        from e:/Ruby30-x64/lib/ruby/3.0.0/fiddle/import.rb:86:in
`block in dlload'
        from e:/Ruby30-x64/lib/ruby/3.0.0/fiddle/import.rb:77:in `collect'
        from e:/Ruby30-x64/lib/ruby/3.0.0/fiddle/import.rb:77:in `dlload'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui/ffi.rb:12:in
`<module:FFI>'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui/ffi.rb:7:in
`<module:LibUI>'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui/ffi.rb:6:in
`<top (required)>'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui.rb:21:in
`require_relative'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui.rb:21:in
`<module:LibUI>'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/libui-0.0.10/lib/libui.rb:6:in
`<top (required)>'
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in
`require'
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in
`require'
        from e:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/glimmer-dsl-libui-0.1.4/lib/glimmer-dsl-libui.rb:31:in
`<top (required)>'
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in
`require'
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:160:in
`rescue in require'
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:149:in
`require'
<internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in
`require': cannot load such file -- glimmer-dsl-libui (LoadError)
        from <internal:e:/Ruby30-x64/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in
`require'

I double checked the dll file path and the dll file does exist.

I installed both the Ruby MSYS and MING toolchains by the way. I did see an odd error in the beginning:

mkdir: cannot change permissions of โ€˜/dev/shmโ€™: Permission denied 
mkdir: cannot change permissions of โ€˜/dev/mqueueโ€™: Permission denied

I am not sure if they are related at all.

Do you have any idea what is going on?

How to provide TableModelHandler ColumnType for different columns

Hi,

I have a new question. I noticed that in your implementation of examples/basic_table.rb you provide a single static value for model_handler.ColumnType:

model_handler.ColumnType   = rbcallback(4) { 0 }

examples/basic_table_image.rb also had similar code:

model_handler.ColumnType   = rbcallback(4) { 1 } # Image

This works well if all columns are the same type, but what if the columns are of different types like one text column and one image column? How do you modify the code to handle the variety of columns? And, do you have a quick link/reference for what each column type value is for all column types?

I'd be very grateful for any help with this.

Andy

Fiddle::Pointer and Garbage-Collection Protection

Hey there kojix2,

First off - thank you for the example(s) provided for coloured text.

It works fine on my system. The API is a bit complicated, assumingly due
to upstream libui and how it handles strings (attributed/unattributed), but
the end result works - I got the green and red colours.

I also realized that we can already display images as well, even if this
requires embedding into some table - but I realized that I can just display a
single example as-such and it works too, so this is kind of "displaying
an image in libui / ruby-libui".

Anyway.

I started a project that is similar to gtk_paradise (for ruby-gtk)
in that it tries to enhance the official bindings for libui, which
you make available via the ruby bindings to LibUI here. I thus
did so for libui, or ruby-libui that you provide, as well.

See here:

https://rubygems.org/gems/libui_paradise

Please do not be too critical of the code - it is one giant
pile of hack upon hack upon hack upon hack. But it was fun
to modify Fiddle::Pointer - that even works! It feels like
oldschool evil.rb (if anyone remembers it ... shapechanging
objects ... the button {} idea I had back then when evil.rb
was around. No idea what happened to it after ruby 1.8.7
though ...)

I also managed to create tons of segfaults already via
ruby-libui. :D

It is a bit difficult to know why something segfaulted, so
I try to make only small changes, see what breaks and
what does not break, and continue. In pure ruby we get
better results and informations, e. g. which particular
line caused the issue. We can also use pp caller() -
I am not sure if something like this is available for
libui, but this is an aside.

This brings me to the issue request here, though.

I looked at your examples and in some of them you add code
that protects against garbage collection segfaults (I think).

For instance, in the file basic_draw_text.rb you have this
code part including the comment explaining why it is done:

handler.Draw         = handler_draw_event
# Assigning to local variables
# This is intended to protect Fiddle::Closure from garbage collection.
handler.MouseEvent   = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.DragBroken   = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.KeyEvent     = (c4 = Fiddle::Closure::BlockCaller.new(0, [0]) {})

I could comment out the last two lines, via '#', but when I also comment out
the "handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})"
part then the program segfaults/crashes at once. So I understand that the
code you use there is necessary and mandatory to make the program
work - otherwise it will crash.

But!

In my opinion this is not very elegant. It is some kind of boilerplate code.

Would it be possible that there could be a more elegant solution offered?

I can not recommend a particular solution as such, because I do not know
the internals or how C really works (pointers are complicated for me),
and I don't know enough about the ruby-to-C bridge. I know a little
bit, but not enough to understand what is going on in the end.

What I am thinking is to have some kind of API, directly onto
toplevel LibUI, that could be used to activate garbage protection
or the like.

In other words: something that is a single line, that could replace ad-hoc
code like the above. That way we could do something like:

UI.garbage_protection
UI.anti_segfaults

Or something like that. I don't propose those names, but just as an example,
something that could be used that then allows us to write code that could
break due to garbage collection kicking in otherwise. Just like the trick
you do by assigning to variables, but just without having to do that in
a given .rb file.

This is not the only instance where BlockCaller is used.

For example:

basic_table.rb:              blockcaller = Fiddle::Closure::BlockCaller.new(*args, &block)
basic_area.rb:               handler_draw_event   = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, area_draw_params|
basic_table_image.rb:        blockcaller = Fiddle::Closure::BlockCaller.new(*args, &block)
histogram.rb:                handler.MouseEvent   = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})

So it is used in the more complicated examples.

From my point of view this is all "necessary, protective boilerplate code", but I
think that when an end-user is making use of libui - which, by the way, works
great on windows out-of-the-box - then the end-user should not have to be
concerned with this, IMO, if it can be avoided. But as said, I don't fully
understand it - I thought that assigning to just one variable should suffice,
but the example of basic_draw_text.rb shows that this may require more
local variables to exist.

API-wise I don't really know how to best implement this, and don't worry
if that needs time to think through and design, e. g. end-of-the-year changes
only. :)

I just wanted to mention this in regards to from an end-user perspective,
when you think about user interface elements then having to think about
fiddle-closures and segfaults is a bit distracting. I understand that ruby
is ultimately just cool syntactic sugar over C, but ideally it would be great
if we could think just about it from the "assumed" ruby side - the one matz
mentioned a long time ago in the interview from 2003 (
https://www.artima.com/articles/the-philosophy-of-ruby
).

One of my favourite matz quotes is still this one he gave almost 20 years
ago:

"Often people, especially computer engineers, focus on the machines. They think, "By doing this, the machine will run faster. By doing this, the machine will run more effectively. By doing this, the machine will something something something." They are focusing on machines. But in fact we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves."

Anyway, thanks for reading, please as always feel free to close/disregard/implement-as-you-see fit - this is mostly feedback anyway. \o/

PS: I really think many ruby folks are unaware of libui. Even the example of the RING programming language, they added bindings to libui in 2020. But when I looked at old changelogs then libui itself is already available since 2015 ... so we now have +6 years. Even if RING is still fairly young, I think people often don't quite know about alternatives. I had a look at gtk2-based applications on rubygems.org recently and was surprised to see how many used to exist, although they were created largely from 2009 to 2015 or so only.

At any rate this was just mostly information - sorry for
creating so many issues. I think there are still many
ruby users who never heard of libui before; I only found
it indirectly, via ruby-gtk and looking at projects on
github pages.

On that particular side note, I also accidentally found
the Ring programming language, by searching tutorials for
libui. :D

https://github.com/ring-lang/ring/tree/master/extensions/ringlibui

They also show some drawing-shape examples, which is quite nifty.
Ultimately we could use that to build more GUI elements.

(Ring itself is not as elegant as ruby, though, and the total
download size was in the range of ~400 MB or so, which is just
insane ... but from a GUI-point of view I think Ring does
bring in a fresh idea into working with computers.)

Arc not working on Windows

I tried this example (altered from examples/basic_area.rb to have an arc):

require 'libui'

UI = LibUI

UI.init

handler = UI::FFI::AreaHandler.malloc
handler.to_ptr.free = Fiddle::RUBY_FREE
area    = UI.new_area(handler)
brush   = UI::FFI::DrawBrush.malloc
brush.to_ptr.free = Fiddle::RUBY_FREE

handler_draw_event = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, area_draw_params|
  path = UI.draw_new_path(0)
  UI.draw_path_arc_to(path, 50, 50, 140, Math::PI*2, Math::PI, 1)
  UI.draw_path_end(path)
  brush.Type = 0
  brush.R = 0.4
  brush.G = 0.4
  brush.B = 0.8
  brush.A = 1.0
  area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
  UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
  UI.draw_free_path(path)
end

handler.Draw         = handler_draw_event
handler.MouseEvent   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.MouseCrossed = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.DragBroken   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.KeyEvent     = Fiddle::Closure::BlockCaller.new(0, [0]) {}

box = UI.new_vertical_box
UI.box_set_padded(box, 1)
UI.box_append(box, area, 1)

main_window = UI.new_window('Basic Area', 400, 400, 1)
UI.window_set_margined(main_window, 1)
UI.window_set_child(main_window, box)

UI.window_on_closing(main_window) do
  UI.control_destroy(main_window)
  UI.quit
  0
end
UI.control_show(main_window)

UI.main
UI.quit

It does not work on Windows (it runs and closes right away without giving me any error).

I am not sure if there is an issue in LibUI (Ruby) or libui (C), so I am reporting.

Arcs work fine on the Mac and Linux by the way.

[Question / Documentation] Support on non-linux platforms?

Hey there kojix2 - you are the same guy who is also active at
ruby-gtk right? :) So great to see libui! Hopefully this can be
useful as an additional platform (probably easier to get to
work than ruby-gtk for example).

Which brings me to my question - perhaps that question can
be answered in the main README so no need to answer
this here I suppose; README is great because more people
can read it.

Anyway - my question specifically is: how is the windows support
that is, libui working on windows? Can it work "natively" aka
without WSL? (I know that ruby + WSL works very well; I can
even use ruby-gtk on windows via WSL, but something
native that is easier to install on windows would be GREAT.
I solve my personal needs on linux via the commandline,
but for elderly people, this would be great.)

Anyway, hopefully libui can remain active! I look forward to
some advanced styling via CSS too. :-) (Not sure if this
already works, I have not yet worked through the examples
so it will take me a while to get familiar with libui)

ARM64/AARCH64 Support

I got a new Mac M1 CPU (ARM64/AARCH64) computer and the first thing I did was try LibUI, and it didn't work (clearly noting have 'x86_64', need 'arm64e'):

/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle.rb:61:in `initialize': dlopen(/Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/vendor/libui.dylib, 0x0009): tried: '/Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/vendor/libui.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e')), '/usr/local/lib/libui.dylib' (no such file), '/usr/lib/libui.dylib' (no such file) (Fiddle::DLError)
	from /Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle.rb:61:in `new'
	from /Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle.rb:61:in `dlopen'
	from /Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle/import.rb:86:in `block in dlload'
	from /Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle/import.rb:77:in `collect'
	from /Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/fiddle/import.rb:77:in `dlload'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui/ffi.rb:10:in `<module:FFI>'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui/ffi.rb:5:in `<module:LibUI>'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui/ffi.rb:4:in `<top (required)>'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui.rb:19:in `require_relative'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui.rb:19:in `<module:LibUI>'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/libui-0.0.13/lib/libui.rb:4:in `<top (required)>'
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from /Users/andymaleh/.rvm/gems/ruby-3.1.0@glimmer-dsl-libui/gems/glimmer-dsl-libui-0.4.20/lib/glimmer-dsl-libui.rb:35:in `<top (required)>'
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:160:in `require'
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:160:in `rescue in require'
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
<internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- glimmer-dsl-libui (LoadError)
	from <internal:/Users/andymaleh/.rvm/rubies/ruby-3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'

It would be cool if you could figure out a way to compile LibUI for ARM64 on Mac and AARCH64 on Linux.

Question: Why choose `fiddle` rather than `ffi`?

Hi @kojix2

The ffi seems more idiomatic for Ruby, for example:

# ffi
attach_function :puts, [ :string ], :int

# fiddle
floor = Fiddle::Function.new(
          libm['floor'],
          [Fiddle::TYPE_DOUBLE],
          Fiddle::TYPE_DOUBLE
        )

As you can see, in ffi we write just symbols directly to represent C types.

So, I suspect there might be some technical reasons for the use of fiddle rather than ffi. What are them?

[Possible bug or strange behaviour] On 2nd run the libui window is black

Hey there kojix2,

I may have found a bug or at the least a weird behaviour.

First let me show the image - it shows a black window:

https://i.imgur.com/Sng4FNl.png

Next, here is how you can reproduce the behaviour:

First I took the code you showcase in the examples. I will copy/paste it next,
the only change I made was adding "class Button" so I can run this via
"Button.new":

    require 'libui'

    UI = LibUI

    UI.init

    class Button

      def initialize
        main_window = UI.new_window('hello world', 300, 200, 1)
        button = UI.new_button('Button')
        UI.button_on_clicked(button) do
          UI.msg_box(main_window, 'Information', 'You clicked the button')
        end
        UI.window_on_closing(main_window) do
          puts 'Bye Bye'
          UI.control_destroy(main_window)
          UI.quit
          0
        end
        UI.window_set_child(main_window, button)
        UI.control_show(main_window)
        UI.main
        UI.quit
      end

    end

Next, start irb. Do a:

require './button.rb'

or require_relative.

Then do:

Button.new

This is now important! On the first run it works fine. No error.

But!

After you close the window, and do:

Button.new

again, then this black window shows up. It looks to me as if it is
re-using some old data perhaps? Otherwise I would not know
why the second time it is run is different to the first run.

How did I discover this behaviour?

In one of my projects I use libui. I start it via a REPL, similar
to irb. First run is fine but second run always has this black
window. Perhaps I did something wrong, but the behaviour
by libui is quite strange - for instance, via ruby-gtk3 it works
just as expected, I always get the same widget when I run
it without any black window suddenly.

Small bug (I think) in examples/ directory, at the file called draw_text.rb

Heya kojix2,

I noticed you extended the examples, so I went on to test things. :D

Unfortunately it fails to me as superuser:

ruby draw_text.rb 

The error I get is:

/root/.gem/gems/libui-0.0.12/lib/libui/ffi.rb:22:in `call': no implicit conversion of String into Integer (TypeError)
        from /root/.gem/gems/libui-0.0.12/lib/libui/ffi.rb:22:in `uiOpenTypeFeaturesAdd'
        from /root/.gem/gems/libui-0.0.12/lib/libui/libui_base.rb:39:in `public_send'
        from /root/.gem/gems/libui-0.0.12/lib/libui/libui_base.rb:39:in `block (2 levels) in <module:LibUIBase>'
        from draw_text.rb:66:in `make_attribute_string'
        from draw_text.rb:132:in `<main>'

I am not entirely sure where the error is (I find it not so easy to discover ffi-related errors in general) but I wanted to mention this nonetheless. Please disregard this message if it works for you (I use libui gem 0.0.12, but I used the git clone of the repository here, so not sure if that has anything to do with it or not; I mention it just in case). Thanks for reading!

Organising on https://github.com/kojix2 ?

Hey there kojix2,

Sorry for misusing the issue tracker here. This is not specific to LibUI, but instead I have a question or
suggestion for your website/homepage at the least on github: https://github.com/kojix2

You have a lot of different projects, including (if I understood it correctly) various bioinformatics-related
projects, as well as several in crystal. I actually started to learn crystal but I am slow, so ... who knows
when I'll understand crystal better. :D

Anyway.

Some time ago I started to be more serious about one of my own bioinformatics-related project, and
while my TODO list is huge there, I also decided that I want to be able to generate graphics - ideally
even interactive via a GUI, but also in a way to allow one to generate graphics and plots and charts
that can be published in a scientific paper (ideally), without the end user needing to know everything
about HOW these graphs are generated. I want to simplify this.

I looked at various options, gnuplot and so forth, but right now I have settled for ImageMagick +
RMagick, simply because I seem to be able to more easily do what I think I want to do. But there
is also GR and I think you are one of those who maintain GR. I have only recently started to look
at it, already generated some charts with it (as .png files) and that works well.

Ok - so this was just the lengthy introduction to the issue here, so let me get back to what I mean.

If you look at your homepage on github at https://github.com/kojix2 it seems as if you have 159
repositories, probably some are inactive, some are just clones of other repositories so probably
not all of these were started by you. But it's still quite a lot, and I am not even sure how many
bioinformatics-specific libraries or applications you have or maintain there. I have a peek look
every now and then, but I get distracted by tons of things on the internet, so my attention span
is shorter than a squirrel on a sugar-nut rush.

If you ever have some time on some weekend in the future, do you think you could re-organise
the main webpage a little bit more? I can't say how, but just so that on a first visit to your homepage
there, we could more readily see which projects seem more important? I noticed you did something
similar in regards to bio-ruby specific gems. Perhaps you could do something like this for your
homepage too, e. g. something like:

Project 1: "this is about cats" -> Link
Project 2: "this is about dogs" -> Link
Project 3: "this is about ninja" -> Link

And so forth. Just so that a visitor can get a better overview with a little bit of context.

You kind of already do so, e. g. via "Plotting / Data" or "Bioinformatics", but I am not sure
which of these projects are more relevant or more important. I'd love to integrate some of
the projects you created/maintain (such as https://github.com/ruby-on-bioc/bio-bigwig)
but I don't quite know which ones are more important or more relevant, and I kind of have
to understand them first a little bit better before I can add code to support something (as
otherwise my code will be broken or bad, and then others can't really use broken code
if I don't understand the problem domain at hand well enough.)

Anyway, sorry for the issue, please feel free to ignore/close/disregard as it fits.

PS: By the way, as you have both GR.rb and GR.cr it would be interesting to compare
similar tasks there, e. g. 3 samples each doing the same, and how it looks in ruby and
how it looks in crystal. I assume the crystal variant will be slightly longer because
crystal requiring type information sometimes, but it may be interesting to see
advantages and disadvantages. Perhaps larger and more complicated plots take
longer in ruby.

Turing Pattern

Hi,

Congrats on the new release! examples/draw_text.rb and examples/spectrum.rb worked nicely!

The Turing Pattern example does work, but I do not see anything resembling waves with it. I made sure numo-narray gem is installed.

Here is a screenshot from Linux (starting didn't change anything):
libui-linux-turing-pattern

Here is a screenshot from Mac:
Screen Shot 2021-11-23 at 10 38 02 AM

Would you mind sharing a screenshot or more to demonstrate how the Turing Pattern example is supposed to look like when it is working well?

libui-ng related methods: how to use it?

Hey there kojix2,

I saw the changelog - for instance in ffi.rb:

try_extern 'void uiComboboxClear(uiCombobox *c)'

So I was thinking I could use .clear() on a combobox. But when I tested in irb,
the method name was not showing up (or perhaps I made a mistake).

IF it is possible to clear a combo box, could a simple example be added that
shows how this could be done? Or perhaps what the name of the method
may be.

I tried via irb but I could only see these methods:

LibUI.combobox_append 
LibUI.combobox_on_selected
LibUI.combobox_selected    
LibUI.combobox_set_selected

Does one have to do something special to tap into that ffi.rb related functionality?

Addition of another example? Basic colour table - see Andy's example in glimmer-libui-dsl

Heya kojix2 (and Andy and everyone else reading this),

Andy added TONS of examples to glimmer-libui-dsl; at this point he is lightning speed ahead of
everyone else in regards to ruby + libui. :D

I regularly look through his examples to see what I can steal, I mean, borrow. :P

One example that caught my eye was this one here:

examples/basic_table_color.rb

Image:

https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-table-color.png

The link to the ruby source code is here:

https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/examples/basic_table_color.rb

(It's the raw ruby code, so it can be copy/pasted).

Andy evidently uses an array to colourize entries:

data = [
  [['cat', :red]      , ['meow', :blue]                  , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],

So I suppose R G B stands for red green blue (I like that he used logical variables!)

I assume the :red, :blue and so forth are the colours. I actually use that in other ruby
projects myself - kind of neat to see DSLs being to some extend similar.

Andy then uses a higher level DSL for the actual code implementation:

table {
  text_color_column('Animal')
  text_color_column('Sound')

Pretty epic.

Unfortunately I have absolutely no idea how Andy did this. I can not for the life of me figure out
upstream libui; the documentation is so sparse ... but evidently these things DO work. So I am having
a bit of a knowledge gap here.

So here comes my request:

  • Would it be possible for ruby libUI here to add a simple example for ONE entry in a table?
    Does not have to include any images or so; I just want to see how to colourize entries in a
    table. For instance, first row light yellow, second row white background, third row light
    yellow and so forth. Not sure if either of you two know how to do this in "raw" libui but it
    would be great if libui itself could have such a simple example. (I also have to admit that
    pointers and malloc are above my level of understanding ... I really should have learned C
    properly before using ruby but ruby is so much more fun :P )

LibUI::FFI::DrawBrush LinearGradient & RadialGradient Examples

The LibUI::FFI::DrawBrush object is supposed to support LinearGradient with Type=1 and RadialGradient with Type=2 if I understand correctly.

In those cases, these attributes could be set:

  • X0
  • Y0
  • X1
  • Y1
  • OuterRadius
  • Stops

Could you please provide examples of paths with draw_fill having LinearGradient and RadialGradient (perhaps applied to a rectangle)?

Again, my lack of expertise in Fiddle makes me prefer to rely on you as a reference for how to do advanced things with it.

Thanks

[Question] Field Edit sign restriction visible in GUI?

is it possible with LibUI to restrict Signs like %$()= and spaces etc. in an Field Edit?

I imagine if i edit a Field and press defined restricted Signs on my Keyboard the Field will ignore this Signs at all..

Thanks!

Glimmer DSL for LibUI Wins Fukuoka Ruby 2022 Special Award

https://andymaleh.blogspot.com/2022/02/glimmer-dsl-for-libui-wins-fukuoka-ruby.html

http://www.digitalfukuoka.jp/topics/187?locale=ja

This is just a celebratory issue and a big thanks to @kojix2 for contributing to the win of Glimmer DSL for LibUI at the 2022 Fukuoka Ruby Award Competition!

Take this as a great encouragement that the C libui and LibUI Ruby bindings have won indirectly too after Glimmer DSL for LibUI has been presented to and reviewed by Matz, the creator of Ruby, at the 2022 Fukuoka Ruby Award Competition!

I hid from you before the fact that Glimmer DSL for LibUI got selected as a finalist in Fukuoka Ruby Award Competition 2022 because I wanted to receive the final results first, which just came back!

Cheers and keep LibUI alive and greatly useful!!!

CC @rubyFeedback

LibUI::FFI::DrawStrokeParams.Dashes Example

Hi,

I saw this code in examples/histogram.rb:

  dsp = UI::FFI::DrawStrokeParams.malloc
  dsp.Cap = 0 # flat
  dsp.Join = 0 # miter
  dsp.Thickness = 2
  dsp.MiterLimit = 10 # DEFAULT_MITER_LIMIT
  dashes = Fiddle::Pointer.malloc(8)
  dsp.Dashes = dashes
  dsp.NumDashes = 0
  dsp.DashPhase = 0

I am curious about how to supply a dashes array to dsp.Dashes. Could you please provide an example of how to do that?

Thanks.

Drawn text attributed string background attribute does not work on Windows

I tried this altered version of examples/basic_draw_text.rb and text attributed string background did not change:

require 'libui'

UI = LibUI

UI.init

handler = UI::FFI::AreaHandler.malloc
handler.to_ptr.free = Fiddle::RUBY_FREE
area    = UI.new_area(handler)

# Michael Ende (1929-1995)
# The Neverending Story is a fantasy novel by German writer Michael Ende,
# The English version, translated by Ralph Manheim, was published in 1983.

TITLE = 'Michael Ende (1929-1995) The Neverending Story'

str1 = \
  '  At last Ygramul sensed that something was coming toward ' \
  'her. With the speed of lightning, she turned about, confronting ' \
  'Atreyu with an enormous steel-blue face. Her single eye had a ' \
  'vertical pupil, which stared at Atreyu with inconceivable malignancy. '

str2 = \
  '  A cry of fear escaped Bastian. '

str3 = \
  '  A cry of terror passed through the ravine and echoed from ' \
  'side to side. Ygramul turned her eye to left and right, to see if ' \
  'someone else had arrived, for that sound could not have been ' \
  'made by the boy who stood there as though paralyzed with ' \
  'horror. '

str4 = \
  '  Could she have heard my cry? Bastion wondered in alarm. ' \
  "But that's not possible. "

str5 = \
  '  And then Atreyu heard Ygramuls voice. It was very high ' \
  'and slightly hoarse, not at all the right kind of voice for that ' \
  'enormous face. Her lips did not move as she spoke. It was the ' \
  'buzzing of a great swarm of hornets that shaped itself into ' \
  'words. '

str = ''
attr_str = UI.new_attributed_string(str)

def attr_str.append(what, color)
  case color
  when :red
    color_attribute = UI.new_background_attribute(0.0, 0.5, 0.0, 0.7)
  when :green
    color_attribute = UI.new_background_attribute(0.5, 0.0, 0.25, 0.7)
  end
  start = UI.attributed_string_len(self)
  UI.attributed_string_append_unattributed(self, what)
  UI.attributed_string_set_attribute(self, color_attribute, start, start + what.size)
  UI.attributed_string_append_unattributed(self, "\n\n")
end

attr_str.append(str1, :green)
attr_str.append(str2, :red)
attr_str.append(str3, :green)
attr_str.append(str4, :red)
attr_str.append(str5, :green)

Georgia = 'Georgia'

handler_draw_event = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, adp|
  area_draw_params = UI::FFI::AreaDrawParams.new(adp)
  default_font = UI::FFI::FontDescriptor.malloc
  default_font.to_ptr.free = Fiddle::RUBY_FREE
  default_font.Family = Georgia
  default_font.Size = 13
  default_font.Weight = 500
  default_font.Italic = 0
  default_font.Stretch = 4
  params = UI::FFI::DrawTextLayoutParams.malloc
  params.to_ptr.free = Fiddle::RUBY_FREE

  # UI.font_button_font(font_button, default_font)
  params.String = attr_str
  params.DefaultFont = default_font
  params.Width = area_draw_params.AreaWidth
  params.Align = 0
  text_layout = UI.draw_new_text_layout(params)
  UI.draw_text(area_draw_params.Context, text_layout, 0, 0)
  UI.draw_free_text_layout(text_layout)
end

handler.Draw         = handler_draw_event
# Assigning to local variables
# This is intended to protect Fiddle::Closure from garbage collection.
handler.MouseEvent   = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.DragBroken   = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
handler.KeyEvent     = (c4 = Fiddle::Closure::BlockCaller.new(0, [0]) {})

box = UI.new_vertical_box
UI.box_set_padded(box, 1)
UI.box_append(box, area, 1)

main_window = UI.new_window(TITLE, 600, 400, 1)
UI.window_set_margined(main_window, 1)
UI.window_set_child(main_window, box)

UI.window_on_closing(main_window) do
  UI.control_destroy(main_window)
  UI.quit
  0
end
UI.control_show(main_window)

UI.main
UI.quit

I am not sure if this is an issue in LibUI (Ruby) or libui (C), so I am reporting.

Works fine on Mac and Linux.

libui-ng - "beta" ffi for it, for "early testing"?

Hey there kojix2,

I saw your activity/issue tracker in regards to libui-ng.

cody271 wrote about libui-ng needing more time before a
"milestone release" (or however he calls the first
major release of libui-ng, which as far as I understand
has not yet been released).

I would, however had, already like to test libui on
linux specifically, via ruby, if that is possible. This
of course needs the ffi-specific code you wrote already
(for andlabs libui), and I assume this is not yet adjusted
to libui-ng, since the libui-ng code has some changes
listed in the CHANGELOG file.

As far as I understand the ffi-specific code for the ffi-specific
libui code you wrote is stored here:

https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb

So, my first thought is ... what if a second .rb file
is added there, in the same directory, that specifically
deals with the changes of libui-ng only? That is, a single
new .rb file that focuses only on the changes that were
made in libui-ng.

My basic thinking here is the following:

  • People can still use the current ffi.rb for main libui
    (from andlabs) as-is.

  • At the same time, they can also "opt-in" to use that
    second .rb file (which has not yet been created) that
    specifically caters towards the libui-ng specific
    changes.

Then they could perhaps selectively use what they want
to, the original libui, the libui-ng variant or both.

I am not sure if this is too much work, so please take
this only as a rough idea. I know too little about C
and ffi to really understand how it works, so my
thinking may be off here.

I would love to test the changes that cody271 did,
e. g. these ones in particular:

https://raw.githubusercontent.com/libui-ng/libui-ng/master/CHANGELOG.md

Last but not least, I saw you are asking or perhaps
looking for support in maintaining libui. If you
would like to you could add me on github (I think
this is possible via the web-interface; I remember
kou did so for ruby-gnome in the past) and as a
co-maintainer on rubygems.org. My handle on rubygems
is "shevy"; https://rubygems.org/profiles/shevy

The reason I use another nick on github is mostly
because I use primarily rubygems for distributing
code; and github primarily for feedback-related
issues only. (I used git in the past, but I found
it does not align well with my workflow. I am
using mostly ruby scripts for my workflow, e. g.
on rubygems pushing new releases is so much easier
for me via my self-written scripts.)

In regards to trying to help maintain projects:
unfortunately I do not know C, so I can never
really maintain libui as a whole. But I can try
to polish things every now and then if possible
(and wanted).

Perhaps you can also add Andy - I have not asked
him, but he possibly may not mind. Little changes
can probably be easy to do, for instance, documentation
or examples. (For example, if the new changes in
libui-ng are done, I'd love to add examples, so
if I can figure out how these work I could add
them to libui too.)

Anyway, the TL;DR summary for the issue request here is:

  • Can it be considered to add support via a new .rb file for the libui-ng
    specific parts, even if only for linux, as an "early testing" variant?
    (It's fine for me to have this all work better at a later time on windows;
    for now I really just want to test out stuff and see how this may eventually
    work on windows too. On linux I tend to use ruby-gtk3 anyway, but I'd
    love to polish libui on windows as much as that is possible too. And
    early testing may be helpful in this regard)

Main README.md - I think the first example on that file can be simplified a bit

Hello kojix2.

I read in the news that we do no longer have to return 0.

I tried it - and it works! So I assume 0 can now be omitted?

Anyway - the main README has this example right now:

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

The 0 can probably be removed.

Sorry for reporting so many tiny issues but tiny issues are simpler to fix. I am
aware of how much work it can be to look at the libui code and make it pleasant
to use from the ruby side. Omitting 0 is already an improvement! :)

Custom toplevel methods: aiming to enhance LibUI

Heya kojix2,

I would like to try to convince you a little bit of making it "nicer" to work with LibUI. :)

Let me explain what I mean with this.

Consider the following file:

https://github.com/kojix2/LibUI/blob/main/examples/basic_draw_text.rb

In it the text is defined via several method calls (I believe these are method
calls but could be function calls, probably wrappers over ffi and C):

default_font.to_ptr.free = Fiddle::RUBY_FREE
default_font.Family = Georgia
default_font.Size = 13
default_font.Weight = 500
default_font.Italic = 0
default_font.Stretch = 4

And Georgia as constant refers to the string:

Georgia = 'Georgia'

Additionally tons of fiddling have to be done via malloc. This is the hard
part for non-C programmers.

For instance:

handler_draw_event = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, adp|

And several more calls, many of which are not easy to understand.

Would it be possible for LibUI to support simpler APIs? For instance:

LibUI.set_font('Georgia 13')
LibUI.set_font('Georgia 13px')

Or something like that? Could be other names. Data omitted can default
to some values, such as in the example above default value for italic
being 0 and for stretch being 4.

If I understand your point then you want to closely map towards the LibUI C code
to reduce workload for bindings and writing code in ruby, e. g. supporting files
such as:

https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb

That use case is fine. But I am also coming from another use case in that I'd
love to be able to more easily make changes, such as using different fonts,
perhaps colour support and so forth too.

I am not necessarily suggesting that every font-related activity, such as BOLD
text or underline or italic, has to be supported via module LibUI as such. But
the part that I really find difficult is to understand all the malloc-specific things
and I'd like to try to avoid or bypass them if I can. So a toplevel API, or perhaps
a custom class that I can subclass from, or another way, would be really neat.
It could also make LibUI easier to work with directly and people may need
less code e. g. all the font-specific part or malloc-specific part could become
part of LibUI.

If you don't want to have this directly, by default, then perhaps LibUI could
add a secondary helper .rb file? So, we could then perhaps require that
.rb file and in that .rb file you could provide a few helpful methods that can
simplify working with libui code. I am not suggesting that all of ruby-libui
becomes like that, but in particular the malloc specific stuff I'd ideally love
to completely bypass and ignore.

Anyway, if this takes too much time don't worry too much. It is just a
suggestion. :)

Best regards and like always please feel free to close this issue at any
moment in time!

Small harmless warning: instance variable @callbacks not initialized

Hey there kojix2!

I am checking on libui every now and then and noticed you added a new release lately.

I also saw the histogram.rb example - really great! \o/ (I would not know how to do the
same in ruby-gtk for example).

Anyway - this is just a small report.

In the last 0.0.8 gem I get this warning:

libui-0.0.8/lib/libui.rb:50: warning: instance variable @callbacks not initialized

Perhaps @callbacks can be initialized to nil or some other value. Thanks!

DateTimePicker raises a segmentation fault

The DateTimePicker sample generates a segmentation fault and does not work as expected.

I don't know why, but it is possible that access to the memory of the LibUI::FFI::TM structure is happening after it has been released.

Table Selection API

libui-ng recently merged a table selection API:
libui-ng/libui-ng#73

Could you please provide FFI bindings for that API in Ruby so that I could expose in Glimmer DSL for LibUI's GUI DSL?

I got a request about it from a user over here:
AndyObtiva/glimmer-dsl-libui#41

You could make a small release with a newer version of libui-ng and the table selection API only. Afterwards, you could continue to make small releases that add more and more FFI bindings in Ruby for other APIs that got added to libui-ng recently. But, to start, the table selection API should be enough for me to be able to expose it and make a release in Glimmer DSL for LibUI

Two things about libui-ng: one is a build failure with "rake"; the other is a suggestion

Hey there kojix2,

I tried to compile/install libui-ng via the rake command you show in the README.

Specifically:

rake libui-ng:build[hash]

It yields this problem though:

[Rake] Downloading libui-ng
[Rake] Failed. 404 Not Found. Please check https://github.com/libui-ng/libui-ng/archive/hash.zip

Not sure why. Is the URL wrong or has it moved? It probably worked for you in the past
but right now it does not work for me.

There is another request, a small one.

Would it be possible to add code that allows us to distinguish whether we run the libui variant
or libui-ng?

Not sure about the API. Perhaps:

LibUI::VERSION # if you want a generic constant as string

And it could return:

"libui"

or

"libui-ng"

As string.

This may be helpful when we may want to support both libui and
libui-ng, but check whether a specific functionality is available.
At the least if the ruby-libui gem supports both variants.

Would it be possible to add an example for the callback use of a color_button, into the libui gem examples?

Hey there kojix2 (and everyone else handling libui-related code in ruby),

I noticed Andy did a LOT of work in regards to glimmer-libui in the
last 2 or 3 weeks or so. I am watching his changes for inspirational
ideas! Pretty amazing what he did with glimmer. I am trying to
convince him to add ruby-gtk AND gosu to the stack ... but time is
limited I guess so ... anyway. :D

As another example in regards to glimmer-libui, Andy already has almost
40 (!) example files added so far. That's a LOT. He is super-fast when it
comes to writing code. I ported the form example he gave already - pretty
cool. I did not even have that idea. (e. g. user login name form, as an
example, that's pretty useful as a "building block" ...imagine a full
widget series for a desktop-like variant!).

Anyway.

I also noticed, somewhat randomly, that I don't (yet) have a working example
for a color-button in my own dsl-like gem (or wanna-be DSL).

The code Andy wrote in this regard is as follows (copy/paste incoming
but it is super-easy to understand):


require 'glimmer-dsl-libui'

include Glimmer

window('color button', 230) {
  color_button { |cb|
    on_changed do
      rgba = cb.color
      p rgba
    end
  }
}.show

Which is quite cool - that's a proper DSL. My DSL is not
yet anywhere near as advanced; for instance I don't handle
blocks as Andy does in glimmer, so glimmer is better in
this regard.

I tried to reproduce his code, however had, I managed to trip
myself up here. Pointers and procs mess with my head.

I tried to get this variant to work:

LibUI.color_button_on_changed

and "tap" into the pointer such as via:

rgba = cb.color

as Andy does, but I was unable to do so. I seem to only
deal with raw Fiddle::Pointers, so right now I am confused
how Andy managed to get .color method to work (I may
have passed the wrong thing into the callback ...)

If you have the time available, perhaps at some future
weekend, would it be possible to add one example for:

color_button

into the libui gem as-is?

It should not be too much code; I mostly want to see what
I did wrong, because I can not seem to get a "cb.color"
variant to work. Perhaps I just got dumber in the last weeks.

So, a minimal example for "color_button" would be helpful.

As always thank you for reading and potentially considering.

PS: I realized some time ago that I may have to rewrite
my own gem eventually; with Andy pushing the limit I will
also have to extend the DSL-like features, such as:

window {
}

which works for glimmer-libui but not for my variant.

So Andy is going into new frontiers here. I also noticed the
github entry you created, but I have not yet worked through
it. I'll eventually get to it, but I first want to add more examples, screenshots
and so forth, more documentation, more examples and so forth. Then I
am going to rewrite the current code I use; my code base is a bit messy in
its current form right now and I already noticed a few bugs (and fixed a few
of them, but more exist), but some of the examples I have aren't working
as-is; I break too many things. So I have to fix that at a later time as well.

I am investing more time into ruby-gtk3 right now, mostly as that is my "main"
area to explore GUIs, and I have about ~9000 lines of old documentation
from my ruby-gtk2 days that I still have to port into my gtk-related gem.
Just to explain a bit how I have to distribute my time (and that's just
programming-related; reallife isn't all about programming only of course :D;
anyway enough random babbling from me here!).

I get an error when I register two handlers

Problem

Attempting both window_on_closing and window_on_content_size_changed will result in an error.

For example, if you do the following, it will work normally.

#UI.window_on_closing(WINDOW, closing)
UI.window_on_content_size_changed(WINDOW, content_size_changed)

Expected behavior

It is registered normally and works.

Error message

Traceback (most recent call last):
        4: from file.rb:16:in `<main>'
        3: fromlibui-0.0.8/lib/libui.rb:40:in `block (2 levels) in singleton class'
        2: from libui-0.0.8/lib/libui.rb:40:in `with_index'
        1: from libui-0.0.8/lib/libui.rb:40:in `map!'
libui-0.0.8/lib/libui.rb:51:in `block (3 levels) in singleton class': undefined method `<<' for #<Fiddle::Closure::BlockCaller> (NoMethodError)

Code to reproduce

require 'libui'

closing = proc do
  1
end
content_size_changed = proc do
  p "Content size is changed!"
end

UI = LibUI
UI.init

WINDOW = UI.new_window('Example', 300, 300, 0)
UI.window_on_closing(WINDOW, closing)
UI.window_on_content_size_changed(WINDOW, content_size_changed)

UI.control_show(WINDOW)

UI.main
UI.quit

Environments

Ruby version: ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [x64-mingw32]
Gem version: libui (0.0.8)

Button on-click event - simplified API proposal

Hey there kojix2. I hope it is ok to give more suggestions for change. :)

Currently we have to use the API like this for libui:

button = UI.new_button('Button')
UI.button_on_clicked(button) {

I believe we could shorten this a bit.

For example, this would be neater API-wise in my opinion:

button = UI.new_button('Button')
button.on_clicked {

In fact - I am actually doing this in my custom ruby-gtk "bindings".

My long-term dream would be to actually use a "unified"
API like this consistently for both ruby-gtk and libui. That
way I could write the "logic" just once, and then have it
work in ruby-gtk and libui and so forth. (I am ok omitting
features for libui, to keep it simple; just focusing on the
simple stuff, like buttons, text-entries and these things.)

(I understand that time is a limited resource and your
time is limited too - no worries. Just thinking about
this in the long term, say, 6 months to 12 months in
the future from now on.)

The advantage for:

button.on_clicked {

Would be that the moment we have such a method, we can
alias it simply, so people can use whatever they want
to, such as:

button.clicked {

By the way, libui reminds me a bit of ruby shoes from _why.
I think many ruby-users never heard about libui before; I
found it due to your post on ruby-reddit. Perhaps if you feel
libui becomes more stable, consider giving an update in the
middle of next year or something like this.

Anyway, this year is slowly closing, and I am slowly transitioning
into holidays (sort of), so, happy holidays to everyone! Not
sure how holidays are in japan, but ruby always has a xmas
release on 24th of december. :)

I'll probably do some more testing next year or so! Cheers. \o/

Just some feedback on the ORCA - worked for me on the first (actually second) try.

Building an .exe via ORCA worked on the second try. First one I
did not know an .exe would be built, so I interrupted. But then it
continued and eventually I realized that orca was trying to put
it all into an .exe.

The command I used was:

ocra examples/control_gallery.rb --dll ruby_builtin_dlls/libssp-0.dll --dll ruby_builtin_dlls/libgmp-10.dll --dll ruby_builtin_dlls/libffi-7.dll --gem-all=fiddle --output control_gallery.exe

This is just some feedback. It's simpler than any of the alternatives for windows, be it fxruby,
gtk or anything.

I understand that libui possibly isn't trivial to put into a OOP variant (tons of FiddlePointers
which I assume can not be easily modified by pure ruby as such), but as far as simplicity is
concerned, libui beats the other toolkits.

Now I am going the long road to port my ruby-gtk3 applications, if I need them to run on
windows. :) (I failed compiling on windows; got gtk-related missing symbols and then
gave up on it. It's more interesting to add functionality e. g. to libui knowing where it
works, rather than spend more hours in gtk-on-windows when I keep hitting my head
against the wall with it ...)

`rescue in block in dlload': can't load D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/vendor/libui.dll (Fiddle::DLError)

D:/Ruby25/lib/ruby/2.5.0/fiddle/import.rb:89:in rescue in block in dlload': can't load D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/vendor/libui.dll (Fiddle::DLError) from D:/Ruby25/lib/ruby/2.5.0/fiddle/import.rb:86:in block in dlload'
from D:/Ruby25/lib/ruby/2.5.0/fiddle/import.rb:77:in collect' from D:/Ruby25/lib/ruby/2.5.0/fiddle/import.rb:77:in dlload'
from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui/ffi.rb:78:in <module:FFI>' from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui/ffi.rb:74:in module:LibUI'
from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui/ffi.rb:73:in <top (required)>' from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui.rb:28:in require_relative'
from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui.rb:28:in <module:LibUI>' from D:/Ruby25/lib/ruby/gems/2.5.0/gems/libui-0.0.8/lib/libui.rb:6:in <top (required)>'
from D:/Ruby25/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `require'

Adding more than one area underneath a grid makes only the first area show up (Mac)

This code on the Mac shows one area only (note the two disabled lines in the middle of the code).

require 'libui'

UI = LibUI

UI.init

handler = UI::FFI::AreaHandler.malloc
handler.to_ptr.free = Fiddle::RUBY_FREE
area    = UI.new_area(handler)
brush   = UI::FFI::DrawBrush.malloc
brush.to_ptr.free = Fiddle::RUBY_FREE

handler_draw_event = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, area_draw_params|
  path = UI.draw_new_path(0)
  UI.draw_path_add_rectangle(path, 0, 0, 100, 100)
  UI.draw_path_end(path)
  brush.Type = 0
  brush.R = 0.4
  brush.G = 0.4
  brush.B = 0.8
  brush.A = 1.0
  area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
  UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
  UI.draw_free_path(path)
end

handler.Draw         = handler_draw_event
handler.MouseEvent   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.MouseCrossed = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.DragBroken   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler.KeyEvent     = Fiddle::Closure::BlockCaller.new(0, [0]) {}

box = UI.new_vertical_box
UI.box_set_padded(box, 1)
UI.box_append(box, area, 1)

handler2 = UI::FFI::AreaHandler.malloc
handler2.to_ptr.free = Fiddle::RUBY_FREE
area2    = UI.new_area(handler2)
brush2   = UI::FFI::DrawBrush.malloc
brush2.to_ptr.free = Fiddle::RUBY_FREE

handler_draw_event2 = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, area_draw_params|
  path = UI.draw_new_path(0)
  UI.draw_path_add_rectangle(path, 0, 0, 100, 100)
  UI.draw_path_end(path)
  brush.Type = 0
  brush.R = 0.4
  brush.G = 0.4
  brush.B = 0.8
  brush.A = 1.0
  area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
  UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
  UI.draw_free_path(path)
end

handler2.Draw         = handler_draw_event2
handler2.MouseEvent   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler2.MouseCrossed = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler2.DragBroken   = Fiddle::Closure::BlockCaller.new(0, [0]) {}
handler2.KeyEvent     = Fiddle::Closure::BlockCaller.new(0, [0]) {}

box2 = UI.new_vertical_box
UI.box_set_padded(box2, 1)
UI.box_append(box2, area2, 1)
# NOTE: Enable these two lines and area2 will show up
# entry = UI.new_entry
# UI.box_append(box2, entry, 1)

grid = UI.new_grid
UI.grid_append(grid, box, 0, 0, 1, 1, 0, 0, 0, 0)
UI.grid_append(grid, box2, 0, 1, 1, 1, 0, 0, 0, 0)

main_window = UI.new_window('Basic Area', 400, 400, 1)
UI.window_set_margined(main_window, 1)
UI.window_set_child(main_window, grid)

UI.window_on_closing(main_window) do
  UI.control_destroy(main_window)
  UI.quit
  0
end
UI.control_show(main_window)

UI.main
UI.quit

Screen Shot 2021-10-18 at 5 17 49 PM

When enabling the two disabled lines, which add a control underneath the vertical box containing the second area, suddenly it shows up.

Screen Shot 2021-10-18 at 5 19 49 PM

Not sure if this is an issue in LibUI (Ruby) or libui (C), so reporting...

BTW, I discovered this issue while building the GUI for Befunge98's Ruby implementation. You can see a screenshot of the Glimmer DSL for LibUI implementation at the bottom of the project README (gui branch under my fork). It basically constructs a grid of many area controls, capturing keyboard and mouse input from them and maintaining focus with a light gray color for the selected cell. At first, I tried building it with grid, but I encountered the issue above. I rewrote it using vertical_box and horizontal_boxs, and it worked!

LibUI is awesome!

Examples: could an example be added for LibUI.new_scrolling_area?

Hello kojix2 and everyone else,

Would it be possible to add a small example for how LibUI.new_scrolling_area
works?

Use case:

Actually I wrote a tiny ruby-gtk3 application that uses mpv to play local .mp3 files.
This is in a scrolled window, with a vbox, containing each local song via a button.

So I click on the button and then mpv plays the song. This is like the ultimate
minimal "jukebox".

On windows I tested - ffmpeg works, mpv works, libui works too.

And using the buttons works as well, but I'd like them in some scrolling container.

Unfortunately I have not yet managed to make this work. I'll google more to see
if I can find an example via scrolling-area, or perhaps I figure it out on my own
eventually. (The malloc and fiddle parts are over my head unfortunately ... I
should have started with C really ... )

At any rate as always please feel free to close the issue request at any moment
in time how you see fit. I also used glimmer-dsl-libui recently to embed images
into a "libui"-widget (on windows), that works too. I got some weird problems
though related to my own ruby code ... would be cool if fiddle-pointer stuff
could get better support for traceback problems. I kind of miss the introspection
you get with ruby methods. :(

Editable checkbox columns do not fire SetCellValue on checking/unchecking on the Mac

Please try this example and let me know if you think this is a bug in the C libui or if there is a reason why SetCellValue does not fire:

# frozen_string_literal: true

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('Animal sounds', 300, 200, 1)

hbox = UI.new_horizontal_box
UI.window_set_child(main_window, hbox)

data = [
  %w[0 cat 1 meow],
  %w[0 dog 1 woof],
  %w[1 checken 0 cock-a-doodle-doo],
  %w[1 hourse 1 neigh],
  %w[0 cow 0 moo]
]

# Protects BlockCaller objects from garbage collection.
@blockcaller = []
def rbcallback(*args, &block)
  args << [0] if args.size == 1 # Argument types are ommited
  blockcaller = Fiddle::Closure::BlockCaller.new(*args, &block)
  @blockcaller << blockcaller
  blockcaller
end

model_handler = UI::FFI::TableModelHandler.malloc
model_handler.NumColumns   = rbcallback(4) { 2 }
model_handler.ColumnType = rbcallback(4, [1, 1, 4]) do | _mh, _m, column|
  column.odd? ? 0 : 2 # uiTableValueTypeInt : uiTableValueTypeString
end
model_handler.NumRows      = rbcallback(4) { 5 }
model_handler.CellValue    = rbcallback(1, [1, 1, 4, 4]) do |_, _, row, column|
  if column.odd?
    UI.new_table_value_string(data[row][column])
  else
    UI.new_table_value_int(data[row][column].to_i)
  end
end
model_handler.SetCellValue = rbcallback(0, [1, 1, 4, 4, 1]) do |_, _, row, column, val|
  puts [row, column, val].inspect
end

model = UI.new_table_model(model_handler)

table_params = UI::FFI::TableParams.malloc
table_params.Model = model
table_params.RowBackgroundColorModelColumn = -1

table = UI.new_table(table_params)
UI.table_append_checkbox_text_column(table, 'Animal', 0, -2, 1, -2)
UI.table_append_checkbox_text_column(table, 'Description', 2, -2, 3, -2)

UI.box_append(hbox, table, 1)
UI.control_show(main_window)

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.free_table_model(model)
  UI.quit
  0
end

UI.main
UI.quit

Update: I added the ColumnType code you suggested, which was not needed on the Mac where I first ran the code, but is required on Linux.
Update 2: I had the problem on the Mac (I reported before I got a chance to test on Linux, on which it worked when I later tested)

Example for Parent and Child Windows

Can we get a Example for HowTo Code a Main (Parent)Window and open a Child Window from it?

Maybe im to green behind my ears (Level 1 Developer in Praxis) but i dont get it to work.

The Problem is if i open a Window from the Main Window and Press X (SIGKILL?) to close the Childwindow the whole Programm get closed included my Parentwindow

Just one Example will be very helpful for me to get the Syntax :)

Thanks!

callback for UI.timer

You can't write this way.

UI.timer(1000) do
  puts "hello"
  0
end
can't modify frozen Integer: 1000 (FrozenError)

Cannot add callbacks as instance variables to 1000. (This is necessary to avoid garbage collection.)

You can write it this way.

c = Fiddle::Closure::BlockCaller.new(4, [0]) { puts "hello"; 0}
UI.timer(1000, c)

However, the first way of writing is better.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.