libui_paradise 0.1.49
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of libui_paradise might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/README.md +1505 -0
- data/doc/README.gen +1252 -0
- data/doc/SNIPPETS.md +221 -0
- data/doc/TODO.md +14 -0
- data/lib/libui_paradise/autoinclude.rb +9 -0
- data/lib/libui_paradise/domain_specific_language/README.md +5 -0
- data/lib/libui_paradise/domain_specific_language/button.yml +7 -0
- data/lib/libui_paradise/examples/001_basic_button_example.rb +17 -0
- data/lib/libui_paradise/examples/002_basic_table_image.rb +92 -0
- data/lib/libui_paradise/examples/003_font_button.rb +34 -0
- data/lib/libui_paradise/examples/004_date_time_picker.rb +31 -0
- data/lib/libui_paradise/examples/005_msg_box_error.rb +25 -0
- data/lib/libui_paradise/examples/006_histogram.rb +193 -0
- data/lib/libui_paradise/examples/007_combo_box_example.rb +41 -0
- data/lib/libui_paradise/examples/008_simple_notepad_example.rb +23 -0
- data/lib/libui_paradise/examples/009_checkbox_example.rb +82 -0
- data/lib/libui_paradise/examples/010_grid_example.rb +26 -0
- data/lib/libui_paradise/examples/011_fancy_text_example.rb +21 -0
- data/lib/libui_paradise/examples/012_control_gallery.rb +180 -0
- data/lib/libui_paradise/examples/013_midi_player.rb +91 -0
- data/lib/libui_paradise/examples/014_basic_draw_text.rb +134 -0
- data/lib/libui_paradise/examples/015_font_example.rb +91 -0
- data/lib/libui_paradise/examples/016_search_entry_example.rb +16 -0
- data/lib/libui_paradise/examples/017_tabs_example.rb +22 -0
- data/lib/libui_paradise/examples/018_image_example.rb +82 -0
- data/lib/libui_paradise/examples/019_open_file_button_example.rb +24 -0
- data/lib/libui_paradise/examples/020_unicode_text_example.rb +28 -0
- data/lib/libui_paradise/examples/021_spinbutton_example.rb +25 -0
- data/lib/libui_paradise/examples/022_text_example.rb +16 -0
- data/lib/libui_paradise/examples/023_parse_config_file_example.config +6 -0
- data/lib/libui_paradise/examples/023_parse_config_file_example.rb +13 -0
- data/lib/libui_paradise/examples/024_text_view_example.rb +14 -0
- data/lib/libui_paradise/examples/025_scrolling_area.rb +16 -0
- data/lib/libui_paradise/examples/026_colour_button.rb +51 -0
- data/lib/libui_paradise/examples/027_form_example.rb +37 -0
- data/lib/libui_paradise/examples/028_password_entry_example.rb +17 -0
- data/lib/libui_paradise/examples/029_two_buttons_showing_how_to_enable_and_disable_them.rb +32 -0
- data/lib/libui_paradise/examples/030_table_example.rb +51 -0
- data/lib/libui_paradise/experimental/dsl.rb +17 -0
- data/lib/libui_paradise/extensions/extensions.rb +25 -0
- data/lib/libui_paradise/extensions/hash_fiddle_pointer_widgets.rb +129 -0
- data/lib/libui_paradise/extensions/misc.rb +309 -0
- data/lib/libui_paradise/fiddle/pointer.rb +841 -0
- data/lib/libui_paradise/images/LIBUI_PARADISE_LOGO.png +0 -0
- data/lib/libui_paradise/images/README.md +2 -0
- data/lib/libui_paradise/images/form_example.png +0 -0
- data/lib/libui_paradise/libui_classes/area_handler.rb +52 -0
- data/lib/libui_paradise/libui_classes/button.rb +82 -0
- data/lib/libui_paradise/libui_classes/checkbox.rb +37 -0
- data/lib/libui_paradise/libui_classes/color_button.rb +44 -0
- data/lib/libui_paradise/libui_classes/combobox.rb +55 -0
- data/lib/libui_paradise/libui_classes/editable_combobox.rb +51 -0
- data/lib/libui_paradise/libui_classes/entry.rb +80 -0
- data/lib/libui_paradise/libui_classes/font.rb +78 -0
- data/lib/libui_paradise/libui_classes/font_button.rb +40 -0
- data/lib/libui_paradise/libui_classes/grid.rb +55 -0
- data/lib/libui_paradise/libui_classes/hbox.rb +98 -0
- data/lib/libui_paradise/libui_classes/horizontal_separator.rb +41 -0
- data/lib/libui_paradise/libui_classes/image.rb +82 -0
- data/lib/libui_paradise/libui_classes/label.rb +83 -0
- data/lib/libui_paradise/libui_classes/menu.rb +36 -0
- data/lib/libui_paradise/libui_classes/msg_box.rb +97 -0
- data/lib/libui_paradise/libui_classes/msg_box_error.rb +49 -0
- data/lib/libui_paradise/libui_classes/multiline_entry.rb +59 -0
- data/lib/libui_paradise/libui_classes/non_wrapping_multiline_entry.rb +41 -0
- data/lib/libui_paradise/libui_classes/open_file.rb +42 -0
- data/lib/libui_paradise/libui_classes/password_entry.rb +49 -0
- data/lib/libui_paradise/libui_classes/progressbar.rb +41 -0
- data/lib/libui_paradise/libui_classes/radio_buttons.rb +36 -0
- data/lib/libui_paradise/libui_classes/scrolling_area.rb +85 -0
- data/lib/libui_paradise/libui_classes/search_entry.rb +36 -0
- data/lib/libui_paradise/libui_classes/spinbox.rb +55 -0
- data/lib/libui_paradise/libui_classes/tab.rb +39 -0
- data/lib/libui_paradise/libui_classes/table.rb +45 -0
- data/lib/libui_paradise/libui_classes/text_layout.rb +42 -0
- data/lib/libui_paradise/libui_classes/vbox.rb +51 -0
- data/lib/libui_paradise/libui_classes/window.rb +167 -0
- data/lib/libui_paradise/project/project.rb +26 -0
- data/lib/libui_paradise/prototype/README.md +3 -0
- data/lib/libui_paradise/prototype/prototype.rb +101 -0
- data/lib/libui_paradise/requires/require_the_libui_classes.rb +26 -0
- data/lib/libui_paradise/requires/require_the_libui_paradise_project.rb +11 -0
- data/lib/libui_paradise/version/version.rb +17 -0
- data/lib/libui_paradise.rb +1 -0
- data/libui_paradise.gemspec +49 -0
- metadata +164 -0
data/doc/README.gen
ADDED
@@ -0,0 +1,1252 @@
|
|
1
|
+
GOBOLINUX_IS_GREAT
|
2
|
+
ADD_LAST_UPDATE
|
3
|
+
|
4
|
+
## The libui_paradise project
|
5
|
+
|
6
|
+
<img src="https://i.imgur.com/hYf3sum.png" style="margin: 1em; padding: 8px">
|
7
|
+
|
8
|
+
(This image has been partially auto-generated via **cfdg**, then modified
|
9
|
+
by me via **gimp** and ImageMagick - the rounded borders were
|
10
|
+
done via ImageMagick. You can re-use this image if you want to, including
|
11
|
+
the colour-pattern, via a **CC BY 3.0** licence. See the following link
|
12
|
+
for that licence: https://creativecommons.org/licenses/by/3.0/. For
|
13
|
+
cfdg itself, have a look at: https://www.contextfreeart.org/gallery/)
|
14
|
+
|
15
|
+
The **libui_paradise project** aims to enhance the official (upstream)
|
16
|
+
ruby-libui bindings a little bit.
|
17
|
+
|
18
|
+
You can find the upstream ruby-libui bindings, maintained by **kojix2**,
|
19
|
+
here:
|
20
|
+
|
21
|
+
https://rubygems.org/gems/libui
|
22
|
+
|
23
|
+
(Or visit the github page for ruby-libui here via this link:
|
24
|
+
https://github.com/kojix2/LibUI )
|
25
|
+
|
26
|
+
(Be wary of the name that I use on this page - the currently maintained gem is
|
27
|
+
called **libui**; the older gem, which was called **libui-ruby**, is no longer
|
28
|
+
maintained since as of **2019**. In the document here I may call kojix2' gem
|
29
|
+
**ruby-libui**, but the official name is simply **libui**, which refers to the
|
30
|
+
gem mentioned above: https://rubygems.org/gems/libui - I understand that I
|
31
|
+
am using a misnomer when I refer to this as **ruby-libui**, but it helps
|
32
|
+
me remember, so ...)
|
33
|
+
|
34
|
+
Aside from this mentioned goal of **trying to enhance** the upstream ruby-bindings,
|
35
|
+
the **libui_paradise** project also attempts to demonstrate how we could **try to
|
36
|
+
use a DSL** to write less code in the long run; at the least less syntax.
|
37
|
+
|
38
|
+
Less syntax is not automatically a win-win situation, but often it can
|
39
|
+
be very useful.
|
40
|
+
|
41
|
+
Example for this:
|
42
|
+
|
43
|
+
_ = button('Hello world!') # for libui
|
44
|
+
|
45
|
+
You can use a similar variant in ruby-gtk3, for example:
|
46
|
+
|
47
|
+
_ = Gtk::Button.new('Hello world!')
|
48
|
+
|
49
|
+
Or, if you want to use "toplevel-methods", like the above, identical to the
|
50
|
+
first variant:
|
51
|
+
|
52
|
+
_ = button('Hello world!') # for ruby-gtk
|
53
|
+
|
54
|
+
In fact: if you notice the above three lines of code then there is indeed no
|
55
|
+
difference between which toolkit to use between the first variant and
|
56
|
+
the last variant. We could then, in theory, "plug in" different toolkits,
|
57
|
+
be it ruby-gtk, ruby-tk, ruby-libui and so forth. The **glimmer** project
|
58
|
+
is doing this to some extent, as a general DSL wrapper over GUI-related
|
59
|
+
functionality, including the www - see here: https://github.com/AndyObtiva/glimmer
|
60
|
+
|
61
|
+
We could even extend this to the www and generate the appropriate
|
62
|
+
tags that way, by treating HTML tags as "objects". Note that this is
|
63
|
+
"in theory"; in practice there are some shortcomings, or limitations,
|
64
|
+
such as different toolkits not supporting the same widgets or
|
65
|
+
functionality. The old ruby-qt toolkit, for example, required you to
|
66
|
+
connect slots to signals, due to qt requiring this. I do not know if
|
67
|
+
this is still the case or not, but back in the days this was
|
68
|
+
necessary and it complicated using ruby-qt a little bit.
|
69
|
+
|
70
|
+
The **libui_paradise gem** here is highly experimental at this stage
|
71
|
+
and may not work for all use cases, or may have bugs - I am still
|
72
|
+
learning myself here. I want to see which API calls make the most sense
|
73
|
+
in the long run, ideally even across different GUIs as well as the
|
74
|
+
www. (For those of you who have some experience with ruby-gtk this may
|
75
|
+
seem familiar, as pointed out above - API elements such as **.set_text()**
|
76
|
+
or **widget1.add(widget2)**; I kind of learned GUIs first via
|
77
|
+
**ruby-gtk**, which evidently shaped my opinion on GUI layouts
|
78
|
+
to some extent.)
|
79
|
+
|
80
|
+
The official ruby-libui project maintained by kojix2 comes with
|
81
|
+
**13 examples** (August 2021) so far. I assume that more examples
|
82
|
+
may be added over the coming months and years depending on use
|
83
|
+
case, time availability, motivation and so forth. Have a look at
|
84
|
+
the code provided on the github page to understand what is going
|
85
|
+
on - in particular the **histogram** example is really nifty if
|
86
|
+
you want to play around with it **interactively**. It is probably the
|
87
|
+
best example in this regard, because it features interactive and
|
88
|
+
dynamic use in a visual way - you can choose the colours, for
|
89
|
+
example. A spin-button allows for visual change too, but I think
|
90
|
+
colours are more impressive than simple up-and-down counters.
|
91
|
+
|
92
|
+
On windows this may look like so (via kotlin-libui):
|
93
|
+
|
94
|
+
<img src="https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/histogram/histogram-windows7.png" style="margin-left: 2em">
|
95
|
+
|
96
|
+
Also check out kojix2' other examples in ruby-gtk - would be great
|
97
|
+
if we could have the same in libui one day, but this also depends
|
98
|
+
on what upstream libui makes available, unless it is somehow
|
99
|
+
possible to connect multiple shared libraries into libui; then
|
100
|
+
we could perhaps extend libui.
|
101
|
+
|
102
|
+
I am trying to think about ways to simplify the code in these
|
103
|
+
examples as well, so that we can "do more by writing less". But as
|
104
|
+
stated before: this is all **highly experimental** and subject
|
105
|
+
to change. I am going via slow, tiny babysteps here! Constant
|
106
|
+
wins the race in the long run, just remember the turtle versus
|
107
|
+
the rabbit. The rabbit always believed that he would win the
|
108
|
+
race ...
|
109
|
+
|
110
|
+
**kojix2** pointed out that a half-baked or incomplete OOP design may
|
111
|
+
not make a lot of sense in regards to ruby-libui - we have to think a
|
112
|
+
bit about **Fiddle::Pointer** which not everyone may have done before.
|
113
|
+
|
114
|
+
Otherwise you may end up segfaulting everything all over the place
|
115
|
+
(which I did run into already - but it is both scary and fun at the
|
116
|
+
same time!). Subclassing is also difficult to do properly - which
|
117
|
+
functions should be called to create a "proper" subclass? May there
|
118
|
+
be problems as a consequence of trying this? I have no idea right
|
119
|
+
now. This is definitely more related to the C API of ruby than
|
120
|
+
"pure", plain ruby as such. You kind of have to understand the
|
121
|
+
underlying C code to some extent.
|
122
|
+
|
123
|
+
I do not really know C very well; **pointers** are way above my
|
124
|
+
level of understanding, so **kojix2's** point is a fair one
|
125
|
+
to make, since someone may have to maintain a growing code base -
|
126
|
+
this may well be the case here too, so 'defensive programming'
|
127
|
+
is a viable strategy. There are examples where one has to work
|
128
|
+
around ruby's GC too, for instance - this all makes this a little
|
129
|
+
bit more complicated than plain, "pure" ruby code.
|
130
|
+
|
131
|
+
**However had**, at the same I still want to **experiment** and see
|
132
|
+
what may happen with the code in general - which pitfalls may happen
|
133
|
+
or which things could be improved upon. I think the more people use
|
134
|
+
libui and ruby-libui, the better this may become in the long run.
|
135
|
+
Imagine we could almost create a full desktop system based on
|
136
|
+
libui! Even if the original scope never was aimed towards that. :D
|
137
|
+
|
138
|
+
This may then be fast enough for ruby-on-the-desktop, and simple
|
139
|
+
enough to do that, too. Right now this has too many shortcomings;
|
140
|
+
I miss CSS styling in particular. But, in theory, we could do
|
141
|
+
this. Anyone feels clever enough to use ruby as a desktop-UI
|
142
|
+
language via libui? I suppose it still requires some decent
|
143
|
+
knowledge of C ...
|
144
|
+
|
145
|
+
Lots of different people could create widgets and add-ons when
|
146
|
+
this were possible ... but I digress.
|
147
|
+
|
148
|
+
**Write a GUI once, run everywhere** (well ... at the least in
|
149
|
+
theory). This is an excellent idea, even if libui may not be
|
150
|
+
around one day, that idea should be retained for other GUIs
|
151
|
+
in the future.
|
152
|
+
|
153
|
+
It's quite difficult to get GTK and ruby-gtk to work on
|
154
|
+
**windows** - I tried to compile it some weeks ago but I
|
155
|
+
ended up having "missing symbols" error messages afterwards.
|
156
|
+
I managed to get the hello-world.c example working, but the
|
157
|
+
more complicated examples did not work for me.
|
158
|
+
|
159
|
+
On Linux this is much, much easier to do ... I literally just
|
160
|
+
compile GTK, after its dependencies are properly installed (glib,
|
161
|
+
pango, atk, and so forth), and then the ruby bindings maintained
|
162
|
+
largely by kou (and others), and ... it works! At the least
|
163
|
+
on linux.
|
164
|
+
|
165
|
+
(I used to be able to run ruby-gtk2 on windows in the past,
|
166
|
+
a long time ago, using the provided binaries, but sadly upstream
|
167
|
+
GTK developers no longer provide binaries as-is, and there are
|
168
|
+
no binary bundles for ruby-gtk on windows anymore either. I
|
169
|
+
assume it is possible if you know msys2, and the windows
|
170
|
+
platform, but I am no expert on either, so ...)
|
171
|
+
|
172
|
+
**libui** is so much simpler to use on windows than GTK,
|
173
|
+
though - just do **gem install libui** and it'll work,
|
174
|
+
as-is. Literally. That's it. I tried it on my windows
|
175
|
+
laptop and it **does** indeed work. That convinced me
|
176
|
+
that it makes sense to use libui and ruby-libui. The reason it
|
177
|
+
works is because the ruby-libui gem (just called **libui**)
|
178
|
+
bundles the respective binaries, and it is quite small. This
|
179
|
+
would be much harder to do with ruby-gtk.
|
180
|
+
|
181
|
+
Now I am trying to find more awesome examples to showcase
|
182
|
+
what can be done. Who knows - perhaps even CSS may be supported
|
183
|
+
one day (perhaps only on linux though, which limits the
|
184
|
+
benefit of it; ruby-gtk3 does allow for CSS though). A
|
185
|
+
font example has also been provided, so we can upscale,
|
186
|
+
downscale, use different fonts, bold, in colours and so
|
187
|
+
on and so forth now.
|
188
|
+
|
189
|
+
Check out the colours in the file **basic_draw_text.rb**,
|
190
|
+
as courtesy provided by kojix2. That way you can style
|
191
|
+
the content of a widget more easily - only the fiddle-protection
|
192
|
+
against segfault parts is a bit strange, but that's a detail.
|
193
|
+
|
194
|
+
There currently is quite a bit of code to make this work;
|
195
|
+
in the long run I plan to simplify this if possible. **The
|
196
|
+
less code we have to write, the better** - as long as the
|
197
|
+
end code is still **readable**.
|
198
|
+
|
199
|
+
Note that the subclass situation may change eventually; see
|
200
|
+
upstream kojix2 and related discussion for fiddle. For
|
201
|
+
the time being, though, I'll retain my old approach until
|
202
|
+
I am sufficiently content with the project as-is. Right now
|
203
|
+
libui_paradise has way too much undocumented and untested
|
204
|
+
code and I still have not added all examples either (coloured
|
205
|
+
text, for instance, still has to be added; and more image-related
|
206
|
+
examples that are smaller). Stay tuned.
|
207
|
+
|
208
|
+
## How to require the libui_paradise project
|
209
|
+
|
210
|
+
In order to **require the libui_paradise project**, use
|
211
|
+
something like the following:
|
212
|
+
|
213
|
+
require 'libui_paradise'
|
214
|
+
|
215
|
+
More frequently if you look at the **examples/** subdirectory, the
|
216
|
+
following is used instead:
|
217
|
+
|
218
|
+
require 'libui_paradise/autoinclude'
|
219
|
+
|
220
|
+
Note that this particular require call does a few things automatically,
|
221
|
+
which may not always be what you may want to use. So, again - check
|
222
|
+
out the official ruby-libui repository first, including the examples,
|
223
|
+
before having a look at **libui_paradise**. This project here is a
|
224
|
+
tinker-project, very unstable, subject to change - don't use it in
|
225
|
+
production yet.
|
226
|
+
|
227
|
+
In my own projects I tend to use the above autoinclude variant
|
228
|
+
most of the time, because that way I can write less code (omit
|
229
|
+
a few lines).
|
230
|
+
|
231
|
+
## How to get started with ruby-libui and the libui_paradise project?
|
232
|
+
|
233
|
+
Well - as stated elsewhere, I first recommend to you that you look directly
|
234
|
+
at ruby-libui provided by kojix2, in particular the examples that he
|
235
|
+
distributes in the gem. Work through the examples step-by-step, possibly
|
236
|
+
starting with the smallest example, see whether they work (they do,
|
237
|
+
or should) and have a look at how things work - just to get an
|
238
|
+
overview.
|
239
|
+
|
240
|
+
Have a look at the code as well, in order to understand how it
|
241
|
+
works roughly; after some minutes or perhaps a very few hours of tinker-time
|
242
|
+
you should understand quite a bit already, if you already know ruby. Even
|
243
|
+
more so if you did work with GUIs before, including GUIs via a www-interface.
|
244
|
+
|
245
|
+
Then you are recommended to look at the libui_paradise project and look to
|
246
|
+
see what has been added on top of what kojix2 provides. Look at the examples
|
247
|
+
of the libui_paradise project as well (they are a bit simplified compared
|
248
|
+
to the upstream examples; unfortunately a few of them currently do not
|
249
|
+
work), then consider using **libui_paradise/prototype/prototype.rb** in
|
250
|
+
particular. Copy it and adjust it to your project and use case, as-is. You
|
251
|
+
may want to remove the grid that is inside there and use a hbox or a vbox
|
252
|
+
instead, or a padded_hbox and padded_vbox. It's all quite simple actually
|
253
|
+
once you understand the basic API: windows, widgets, buttons, entries.
|
254
|
+
|
255
|
+
For example, a button can be added in this way to a vbox, if you use
|
256
|
+
the libui_paradise gem:
|
257
|
+
|
258
|
+
outer_vbox = padded_vbox # padded means that it will have some padding to the sides
|
259
|
+
button = ui_button('Hello world!') # You can drop the ui_ prefix if you'd like to
|
260
|
+
button.on_clicked {
|
261
|
+
puts 'Hello world!'
|
262
|
+
}
|
263
|
+
outer_vbox.minimal(button) # Use minimal space if possible. Or use .add().
|
264
|
+
|
265
|
+
That's it! Inside of the **.on_clicked {}** block you can run the ruby code
|
266
|
+
that you want to use. A button that is in a container (such as **vbox**) that
|
267
|
+
outputs hello world when clicked. Can't get much simpler than that. \o/
|
268
|
+
|
269
|
+
You can omit the **ui_** part above. I just use it to point out the difference;
|
270
|
+
and because I'd otherwise may have to use "button = button" aka "button = button()"
|
271
|
+
which may be confusing, so I use **ui_button()** instead.
|
272
|
+
|
273
|
+
## Fiddle::Pointer and playing with pointers
|
274
|
+
|
275
|
+
The **ruby-libui bindings** make use of **Fiddle::Pointer** a lot -
|
276
|
+
see the file called **ffi.rb** in the ruby-libui gem ("gem install libui").
|
277
|
+
It's like **magic** to me - scary and awesome at the same time.
|
278
|
+
|
279
|
+
As a consequence the libui_paradise project has to 'handle' pointers
|
280
|
+
as well, indirectly so, via whatever ruby-libui makes available.
|
281
|
+
|
282
|
+
I decided that, at the least for the time being, we will add
|
283
|
+
**ad-hoc code** straight to Fiddle::Pointer. This is not the
|
284
|
+
optimal solution and I do not recommend doing so, even more so as
|
285
|
+
we modify Fiddle::Pointer directly which I don't think is a good
|
286
|
+
idea; it may be better to have some proper data structures and
|
287
|
+
perhaps **subclass** from Fiddle::Pointer instead, and then modify
|
288
|
+
that subclass instead. That may be better. But for the time being,
|
289
|
+
the code here will remain as it is, until we can come up with
|
290
|
+
better ways to deal with the situation. For now **simplicity**
|
291
|
+
rules.
|
292
|
+
|
293
|
+
Some of the examples used require assigment to local variables
|
294
|
+
to avoid the GC to kick in and cause the program to end. This
|
295
|
+
is presently not very elegant - see a discussion between kojix2
|
296
|
+
and kou to improve on this part. For the time being, though,
|
297
|
+
some of the examples require 'boilerplate' assignment to
|
298
|
+
variabless. Stay tuned for improvements in this regard; ideally
|
299
|
+
we can use libui without having to play with pointers ever.
|
300
|
+
|
301
|
+
## Constraints of the libui_paradise gem
|
302
|
+
|
303
|
+
The libui_paradise gem comes with some **constraints**.
|
304
|
+
|
305
|
+
For example, many of the ad-hoc methods on **Fiddle::Pointer**
|
306
|
+
will only work after you called e. g. **ui_vbox** or a
|
307
|
+
similar constructor where we registered which widgets are
|
308
|
+
created (aka the **new_** methods that are available on
|
309
|
+
the **LibUI** 'namespace'). Only when this has happened
|
310
|
+
will that widget become registered in the main Hash.
|
311
|
+
|
312
|
+
That then means, logically, that if you use a method such as:
|
313
|
+
|
314
|
+
check_button = ui_check_button
|
315
|
+
check_button.is_active?
|
316
|
+
|
317
|
+
This will only work if that widget was created already prior
|
318
|
+
to that "method call".
|
319
|
+
|
320
|
+
What this means in practice is that it is best if you
|
321
|
+
**create all the skeleton** (the **basic UI elements**) **before**
|
322
|
+
calling any other code, including on-clicked or on-toggle
|
323
|
+
events. Otherwise you may find nil values and don't
|
324
|
+
know why that is the case so. If this seems too complicated
|
325
|
+
for you, don't worry - the examples distributed via the
|
326
|
+
libui_paradise gem should work fine (except two buggy ones), so
|
327
|
+
the point of this subsection here is to keep your attention to
|
328
|
+
the fact that, as of right now, if you use libui_paradise, the
|
329
|
+
**proper-order-of-elements is important**. Ideally create all
|
330
|
+
the widgets first, before you add additional functionality to them.
|
331
|
+
|
332
|
+
This is admittedly not a very elegant limitation right
|
333
|
+
now, and one day this restrictions may be removed or
|
334
|
+
lifted - but for now, it is a limitation that requires
|
335
|
+
a tiny bit of discipline to work around, for the time being.
|
336
|
+
So, again - it is best to split up the skeleton UI from
|
337
|
+
the function.
|
338
|
+
|
339
|
+
## How to use an 'Open File' button
|
340
|
+
|
341
|
+
I came up with the following solution for now:
|
342
|
+
|
343
|
+
outer_vbox = padded_vbox
|
344
|
+
button_open_file = button('Open file')
|
345
|
+
button_open_file.on_clicked {
|
346
|
+
filename = open_file(window).to_s # This is the part that will open a local file.
|
347
|
+
}
|
348
|
+
outer_vbox << button_open_file # Add the button to the outer-vbox.
|
349
|
+
|
350
|
+
Calling the **.to_s** method on the Fiddle::Pointer yields the actual
|
351
|
+
filename. You can then add more code to deal with this.
|
352
|
+
|
353
|
+
**window** above refers to the **main_window**. See the example
|
354
|
+
**019_open_file_button_example.rb** for how this actually works.
|
355
|
+
|
356
|
+
In the future this may be even further simplified a little, as
|
357
|
+
opening local files is a very common task in most GUIs. A
|
358
|
+
single method probably should suffice for using such a
|
359
|
+
specialized button.
|
360
|
+
|
361
|
+
## How to quit from a ruby-libui widget
|
362
|
+
|
363
|
+
I found that:
|
364
|
+
|
365
|
+
UI.quit
|
366
|
+
|
367
|
+
Works best overall. And seems to suffice as well.
|
368
|
+
|
369
|
+
There are some other calls, such as destroy-control and similar
|
370
|
+
actions, which are probably clean-up related - but by and large
|
371
|
+
**UI.quit** seems to be the main part how to exit from a
|
372
|
+
libui-application.
|
373
|
+
|
374
|
+
I document this here in the event that I forget it in a few
|
375
|
+
months.
|
376
|
+
|
377
|
+
If you use the libui_paradise gem then you can use the
|
378
|
+
following method to use a quit button:
|
379
|
+
|
380
|
+
a_quit_button = ui_quit_button
|
381
|
+
|
382
|
+
If you want another textual description then you can do the
|
383
|
+
following:
|
384
|
+
|
385
|
+
a_quit_button = ui_quit_button(text: 'Open a local file') # That text description would be confusing though
|
386
|
+
a_quit_button = ui_quit_button(text: 'Exit the application') # Much better now! \o/
|
387
|
+
|
388
|
+
## UI.new_button()
|
389
|
+
|
390
|
+
UI.new_button allows us to create a new button.
|
391
|
+
|
392
|
+
Examples:
|
393
|
+
|
394
|
+
button1 = UI.new_button('Text')
|
395
|
+
button2 = UI.new_button('▶')
|
396
|
+
|
397
|
+
## Subclassing
|
398
|
+
|
399
|
+
Currently subclassing from LibUI elements does not work - I simply
|
400
|
+
have no idea how to "subclass" from a **Fiddle::Pointer**. Perhaps we
|
401
|
+
have to build up a data structure that behaves like Fiddle::Pointer
|
402
|
+
but also has methods that allow 'OOP behaviour'. Has anyone tried
|
403
|
+
this yet? I am scared to try considering I already got segfaults ...
|
404
|
+
|
405
|
+
Eventually I may figure this out - or someone else with more knowledge
|
406
|
+
will make this available. We can probably 'fake' subclassing to
|
407
|
+
a pointer somehow ... after all ruby internally has to figure it
|
408
|
+
out as well and probably did so already, on the C-level side.
|
409
|
+
|
410
|
+
## Quickly adding text to a widget
|
411
|
+
|
412
|
+
You can use something like this:
|
413
|
+
|
414
|
+
outer_vbox = ui_vbox
|
415
|
+
outer_vbox.text(
|
416
|
+
'This widget can be used to do xyz.'
|
417
|
+
)
|
418
|
+
|
419
|
+
Again - this modifies **Fiddle::Pointer** so be wary. The second
|
420
|
+
argument is the default one for use in a label / ui_text widget.
|
421
|
+
|
422
|
+
## Working with combo-boxes
|
423
|
+
|
424
|
+
To create a combo-box, do:
|
425
|
+
|
426
|
+
combo_box = ui_combo_box
|
427
|
+
|
428
|
+
You can fill it with an array of entries **on creation-time** via:
|
429
|
+
|
430
|
+
combo_box = ui_combo_box([1,2,3,4])
|
431
|
+
|
432
|
+
This will also focus on the very first element when doing so.
|
433
|
+
|
434
|
+
If you need to do so manually, and focus on another element,
|
435
|
+
you can use the following toplevel method:
|
436
|
+
|
437
|
+
UI.combobox_set_selected()
|
438
|
+
|
439
|
+
To query the currently selected value, use:
|
440
|
+
|
441
|
+
UI.combobox_selected(pointer)
|
442
|
+
|
443
|
+
This is usually done via a **proc {}** object. See kojix2' examples.
|
444
|
+
|
445
|
+
In LibuiParadise a few custom methods were added, such as
|
446
|
+
**.ui_sync_connect()**. This method was added to connect a
|
447
|
+
combo-box to a entry and automatically sync that entry whenever
|
448
|
+
the combo box is changed. See the example **007_combo_box_example.rb**
|
449
|
+
for how this works.
|
450
|
+
|
451
|
+
The **source code** to the combo-box in libui, at the least
|
452
|
+
for UNIX/Linux, can be seen here:
|
453
|
+
|
454
|
+
https://github.com/andlabs/libui/blob/master/unix/combobox.c
|
455
|
+
|
456
|
+
## Error messages and ui_error_message
|
457
|
+
|
458
|
+
In LibUI respectively ruby-libui you can display error messages
|
459
|
+
via a popup window.
|
460
|
+
|
461
|
+
The API is something like this:
|
462
|
+
|
463
|
+
UI.msg_box(main_window, 'Information', 'You clicked the button')
|
464
|
+
UI.msg_box_error(main_window, 'Information', 'You clicked the button')
|
465
|
+
|
466
|
+
The first line shows a normal message box; the second line shows how to
|
467
|
+
use a message box specifically 'adapted' for displaying errors to the
|
468
|
+
end user.
|
469
|
+
|
470
|
+
LibuiParadise makes this available via **ui_msg_box** and **ui_msg_box_error**
|
471
|
+
respectively.
|
472
|
+
|
473
|
+
## Libui Form
|
474
|
+
|
475
|
+
**Form** is a container that takes labels for its contents. This is currently
|
476
|
+
just a stub though - we may have to research this with better examples.
|
477
|
+
|
478
|
+
## Libui Checkbox
|
479
|
+
|
480
|
+
A simple checkbox example in **plain** ruby-libui follows:
|
481
|
+
|
482
|
+
checkbox = UI.checkbox('Checkbox')
|
483
|
+
checkbox_toggle_callback = proc { |ptr|
|
484
|
+
checked = UI.checkbox_checked(ptr) == 1
|
485
|
+
UI.checkbox_set_text(ptr, "I am the checkbox (#{checked})")
|
486
|
+
}
|
487
|
+
|
488
|
+
This may look like so on Linux:
|
489
|
+
|
490
|
+
<img src="https://i.imgur.com/d7qWalZ.png" style="margin-left: 2em; padding: 4px; border: 1px solid black;">
|
491
|
+
|
492
|
+
To query whether a checkbox is **active**, use code such as the
|
493
|
+
following:
|
494
|
+
|
495
|
+
checkbox.is_active?
|
496
|
+
checkbox.active?
|
497
|
+
|
498
|
+
This depends on the modifications to Fiddler::Pointer, so
|
499
|
+
be wary when you use this - there be dragons (perhaps). Most
|
500
|
+
of these modifications are based on **.object_id**, which is
|
501
|
+
registered in a main, toplevel Hash in the
|
502
|
+
**libui_paradise project**. Not very elegant, but simple, and
|
503
|
+
it works (for the most part).
|
504
|
+
|
505
|
+
## Adding a widget into another widget
|
506
|
+
|
507
|
+
I chose the following **API** for this:
|
508
|
+
|
509
|
+
box1.add(box2, 1)
|
510
|
+
|
511
|
+
Note that this is "cheating" a bit because the method **.add()** is defined
|
512
|
+
on **Fiddle::Pointer**. That's scary! Segfaults coming your way. But it
|
513
|
+
also seems to work to some extent. Which is amazing ... :-)
|
514
|
+
|
515
|
+
In ruby-gtk it is quite common to use **.add()**. While **.pack_start()**
|
516
|
+
and **.pack_end()** are available in ruby-gtk as well, I think .add() is
|
517
|
+
the simpler name. We just **add a widget to another widget** - job done.
|
518
|
+
|
519
|
+
(I may also use << as alias to .add() and while << is great, remember
|
520
|
+
that it can not easily be used all the time, e. g. box1 << box2 <<
|
521
|
+
box3 versus box1.add(box2).add(box3) - the latter is a bit more
|
522
|
+
resilient syntax-wise.)
|
523
|
+
|
524
|
+
As stated, **<<** was added as an alias to **.add()** but I am not yet sure
|
525
|
+
if this is a very good idea. It's super-nifty to use << everywhere, but it
|
526
|
+
also changes the syntax of the whole .rb file ... on the other hand, using
|
527
|
+
<< is easier than .add() so ... I'll go with that as well. Remember
|
528
|
+
there is more than one way to do something in ruby - you need to
|
529
|
+
select the variant(s) that work best for you and possibly ignore the
|
530
|
+
other variants.
|
531
|
+
|
532
|
+
Since a while the above can be simplified a bit, as will be shown
|
533
|
+
next.
|
534
|
+
|
535
|
+
Rather than use:
|
536
|
+
|
537
|
+
box1.add(box2, 1)
|
538
|
+
|
539
|
+
You can now do this instead:
|
540
|
+
|
541
|
+
box1.maximal(box2)
|
542
|
+
|
543
|
+
This is a tiny bit longer, but you can omit the ", 1" part, which is
|
544
|
+
nice. The alternative is .minimal(), which defaults to:
|
545
|
+
|
546
|
+
add(second_widget, 0)
|
547
|
+
|
548
|
+
So the only difference between .maximal() and .minimal() will be
|
549
|
+
whether you pass 0 or 1 to the method. See the upstream libui
|
550
|
+
API to understand the difference.
|
551
|
+
|
552
|
+
## Libui Tabs
|
553
|
+
|
554
|
+
The notebook-tab may look like this:
|
555
|
+
|
556
|
+
<img src="https://i.imgur.com/olWQAIJ.png" style="margin-left: 2em">
|
557
|
+
|
558
|
+
## Create a vertical box:
|
559
|
+
|
560
|
+
Use code like this:
|
561
|
+
|
562
|
+
vbox = UI.new_vertical_box
|
563
|
+
|
564
|
+
If you use the libui_paradise gem, you can use this:
|
565
|
+
|
566
|
+
vbox = ui_vbox # or
|
567
|
+
vbox = padded_vbox
|
568
|
+
|
569
|
+
## Adding a horizontal separator
|
570
|
+
|
571
|
+
The method **UI.new_horizontal_separator** can be used to add (or rather
|
572
|
+
first create) a horizontal separator.
|
573
|
+
|
574
|
+
You can then add it via .add() or << if you use the libui_paradise
|
575
|
+
project. Alternatively you can use the toplevel method provided by
|
576
|
+
ruby-libui, since that is what the libui_paradise project is doing anyway.
|
577
|
+
|
578
|
+
To simplify this further, you can do something like this:
|
579
|
+
|
580
|
+
outer_vbox = ui_vbox # I call the most-outer vbox usually outer-vbox
|
581
|
+
outer_vbox.add_hsep
|
582
|
+
# outer_vbox.add_horizontal_separator # Or this variant if you prefer some verbosity instead.
|
583
|
+
|
584
|
+
Or, perhaps better, use a padded vbox:
|
585
|
+
|
586
|
+
outer_vbox = padded_vbox # note that "ui_" is not used here
|
587
|
+
outer_vbox.add_hsep
|
588
|
+
|
589
|
+
I needed this functionality to quickly add horizontal separators for some
|
590
|
+
visual cue in the **User Interface**. Using **.add_hsep** is very
|
591
|
+
convenient and fast to write/type. If you want more verbosity then remember
|
592
|
+
that you can always use the upstream API as-is.
|
593
|
+
|
594
|
+
## Entries in LibUI (ui_entry)
|
595
|
+
|
596
|
+
The official source for an ui_entry for Unix (including Linux) can be read
|
597
|
+
here:
|
598
|
+
|
599
|
+
https://github.com/andlabs/libui/blob/master/unix/entry.c
|
600
|
+
|
601
|
+
Personally I tend to create a new entry element in this way:
|
602
|
+
|
603
|
+
entry = ui_entry
|
604
|
+
|
605
|
+
To set new content to it, do:
|
606
|
+
|
607
|
+
entry.set_text('foobar') # Make sure it is a String; that seems to work better.
|
608
|
+
|
609
|
+
To respond to events look at **OnChanged**.
|
610
|
+
|
611
|
+
It can be set read only via:
|
612
|
+
|
613
|
+
entry.read_only # This has not been added into libui-paradise yet.
|
614
|
+
|
615
|
+
To respond to on-changed events, you can use:
|
616
|
+
|
617
|
+
UI.entry_on_changed()
|
618
|
+
|
619
|
+
Complete example:
|
620
|
+
|
621
|
+
text_changed_callback = proc { |ptr|
|
622
|
+
puts "Current textbox data: '#{UI.entry_text(ptr)}'"
|
623
|
+
}
|
624
|
+
|
625
|
+
text_entry = ui_entry
|
626
|
+
text_entry.set_text('Please enter a command')
|
627
|
+
text_entry.on_changed {
|
628
|
+
text_changed_callback
|
629
|
+
}
|
630
|
+
|
631
|
+
The Proc object has to be passed into the {} block variation.
|
632
|
+
|
633
|
+
The latter uses:
|
634
|
+
|
635
|
+
UI.entry_on_changed(text_entry, text_changed_callback, nil)
|
636
|
+
|
637
|
+
## Grids in LibUI
|
638
|
+
|
639
|
+
The API is quite complex and hard to remember:
|
640
|
+
|
641
|
+
UI.grid_append(grid, entry1, 0, 0, 2, 1, 0, 0, 1, 0)
|
642
|
+
|
643
|
+
Who can remember offhand what these values mean?
|
644
|
+
|
645
|
+
The upstream struct is this:
|
646
|
+
|
647
|
+
struct gridChild {
|
648
|
+
uiControl *c;
|
649
|
+
int left;
|
650
|
+
int top;
|
651
|
+
int xspan;
|
652
|
+
int yspan;
|
653
|
+
int hexpand;
|
654
|
+
uiAlign halign;
|
655
|
+
int vexpand;
|
656
|
+
uiAlign valign;
|
657
|
+
|
658
|
+
// have these here so they don't need to be reallocated each relayout
|
659
|
+
int finalx, finaly;
|
660
|
+
int finalwidth, finalheight;
|
661
|
+
int minwidth, minheight;
|
662
|
+
};
|
663
|
+
|
664
|
+
The documentation for Go has this signature:
|
665
|
+
|
666
|
+
func (g *Grid) Append(child Control, left, top int, xspan, yspan int, hexpand bool, halign Align, vexpand bool, valign Align)
|
667
|
+
|
668
|
+
Append adds the given control to the Grid, at the given coordinate.
|
669
|
+
|
670
|
+
I assume that **uiControl c** refers to the widget that is to be embedded
|
671
|
+
into the grid, so the numbers that follow afterwards are the ones
|
672
|
+
that are important. Let's have a look at them, based on the above API
|
673
|
+
call, and only list these again, without the **()**:
|
674
|
+
|
675
|
+
# left, top, xspan, yspan, hexpand, halign, vexpand, valign
|
676
|
+
# 0, 0, 2, 1, 0, 0, 1, 0
|
677
|
+
|
678
|
+
xspan and yspan refer to width; left and top refer to the position
|
679
|
+
in the grid. hexpand and vexpand means whether the grid-cell will
|
680
|
+
expand horizontally or vertically. halign and valign, I think,
|
681
|
+
are used to align the grid-cell horizontally and vertically, so you
|
682
|
+
can position them exactly in the middle.
|
683
|
+
|
684
|
+
Recently (August 2021) I discovered that you can actually put
|
685
|
+
a button-in-a-button. I don't know whether this is a bug or
|
686
|
+
a feature, but it is hilarious.
|
687
|
+
|
688
|
+
The 'raw' code I used for this was the following:
|
689
|
+
|
690
|
+
UI.grid_append(grid, UI.new_button('3'),0,1,1,1,1,1,1,1)
|
691
|
+
UI.grid_append(grid, UI.new_button('4'),1,1,1,1,1,1,1,1)
|
692
|
+
UI.grid_append(grid, UI.new_button('5'),0,1,1,1,1,0,1,0)
|
693
|
+
UI.grid_append(grid, UI.new_button('6'),1,1,1,1,1,0,1,0)
|
694
|
+
|
695
|
+
This led to the following image:
|
696
|
+
|
697
|
+
<img src="https://i.imgur.com/6sWwWKh.png" style="margin-left: 1em">
|
698
|
+
|
699
|
+
The smaller buttons and the larger buttons can be clicked. They
|
700
|
+
reside in the same grid-cell. I don't know whether this is a
|
701
|
+
bug or a feature really, but this was quite hilarious to see.
|
702
|
+
In the event that I may forget this, I'll keep this here as
|
703
|
+
a reference.
|
704
|
+
|
705
|
+
## Margins in LibUI
|
706
|
+
|
707
|
+
The **margin** property specifies if the window content should have a
|
708
|
+
margin or not. The default value is false, meaning that there will
|
709
|
+
be no margin.
|
710
|
+
|
711
|
+
In order to understand the difference, a visual image may be
|
712
|
+
best - the first image that is shown next shows **no margin**,
|
713
|
+
whereas the second image **shows** a margin.
|
714
|
+
|
715
|
+
<img src="https://cloud.githubusercontent.com/assets/11197111/16465935/804a30d4-3e41-11e6-8189-150e8cddc152.png" style="margin-left: 2em"><br>
|
716
|
+
<img src="https://cloud.githubusercontent.com/assets/11197111/16465906/68304cfe-3e41-11e6-8ae0-3123205ee136.png" style="margin-left: 2em"><br>
|
717
|
+
|
718
|
+
Note that the API name is **margined** rather than **margin** -
|
719
|
+
got me a little while to get used to that name.
|
720
|
+
|
721
|
+
The API in Go is: __func (*Group) SetMargined__ respectively
|
722
|
+
__func (g *Group) SetMargined(margined bool)__. When **true**
|
723
|
+
then the group has margins around the child widgets, as mentioned
|
724
|
+
already.
|
725
|
+
|
726
|
+
The **size** of the margins in use, is, unfortunately, determined
|
727
|
+
automatically by the OS - we currently (2021) do not have control
|
728
|
+
over the size of the margin at hand via **libui**.
|
729
|
+
|
730
|
+
Code examples for 'raw' **ruby-libui** are these:
|
731
|
+
|
732
|
+
UI.window_set_margined(MAIN_WINDOW, 1)
|
733
|
+
UI.group_set_margined(group, 1)
|
734
|
+
|
735
|
+
Because I prefer calling methods on objects, I added this instead:
|
736
|
+
|
737
|
+
MAIN_WINDOW.is_margined
|
738
|
+
MAIN_WINDOW.uses_a_margin # Or this variant.
|
739
|
+
|
740
|
+
Note that we are here faking method-calls on a Fiddle::Pointer, but
|
741
|
+
if we don't pay attention then it looks like **OOP**! If it walks
|
742
|
+
like a duck, quacks like a duck then ... it may be a
|
743
|
+
**Fiddle::Pointer:Duck**!!!
|
744
|
+
|
745
|
+
## Entry
|
746
|
+
|
747
|
+
An entry can be set read only (readOnly: Boolean, aka true or false).
|
748
|
+
|
749
|
+
An entry in libui may look like this:
|
750
|
+
|
751
|
+
<img src="https://raw.githubusercontent.com/parro-it/libui-node/master/docs/media/UiEntry.png" style="margin-left:1em">
|
752
|
+
|
753
|
+
## Borderless windows
|
754
|
+
|
755
|
+
A window that is **borderless: true** will not show any title or
|
756
|
+
outside frame. This may be useful for games and what not.
|
757
|
+
|
758
|
+
## Spinbutton / Spinbox
|
759
|
+
|
760
|
+
You can use:
|
761
|
+
|
762
|
+
UI.new_spinbox
|
763
|
+
|
764
|
+
To create a new spinbox.
|
765
|
+
|
766
|
+
To specify the min and max range, pass them as parameters:
|
767
|
+
|
768
|
+
UI.new_spinbox(0, 100)
|
769
|
+
|
770
|
+
If you use the extensions then you can do this instead:
|
771
|
+
|
772
|
+
ui_spinbox
|
773
|
+
spinbox # this is the simplest variant
|
774
|
+
|
775
|
+
You should be able to set a value via set_value but I have
|
776
|
+
not yet added an example for this.
|
777
|
+
|
778
|
+
Relevant methods are:
|
779
|
+
|
780
|
+
UI.spinbox_on_changed()
|
781
|
+
UI.spinbox_set_value()
|
782
|
+
UI.spinbox_value()
|
783
|
+
|
784
|
+
To set a value:
|
785
|
+
|
786
|
+
spinbox.set_value(42)
|
787
|
+
spinbox.value = 42 # this works as well
|
788
|
+
|
789
|
+
## Create a text-view widget
|
790
|
+
|
791
|
+
A text-view widget shows content, such as the content of a local file.
|
792
|
+
|
793
|
+
In libui the general API for this is:
|
794
|
+
|
795
|
+
UI.new_multiline_entry # this is a textview
|
796
|
+
|
797
|
+
## Control Gallery
|
798
|
+
|
799
|
+
Here is an image, from kotlin-libui, how this may look on windows:
|
800
|
+
|
801
|
+
<img src="https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/controlgallery/controlgallery-windows7.png" style="margin-left: 2em">
|
802
|
+
|
803
|
+
## Enabling / Disabling buttons in libui
|
804
|
+
|
805
|
+
This is, assumingly, already possible via:
|
806
|
+
|
807
|
+
libui/ui.h
|
808
|
+
|
809
|
+
Lines 105 to 107 in a0a9807
|
810
|
+
_UI_EXTERN int uiControlEnabled(uiControl *);
|
811
|
+
_UI_EXTERN void uiControlEnable(uiControl *);
|
812
|
+
_UI_EXTERN void uiControlDisable(uiControl *);
|
813
|
+
|
814
|
+
In ruby-libui this should be possible via:
|
815
|
+
|
816
|
+
LibUI.control_enable()
|
817
|
+
UI.control_enable()
|
818
|
+
|
819
|
+
LibUI.control_disable()
|
820
|
+
UI.control_disable()
|
821
|
+
|
822
|
+
See the example **029_two_buttons_showing_how_to_enable_and_disable_them.rb**
|
823
|
+
in how this works.
|
824
|
+
|
825
|
+
## libui and ruby-libui internals
|
826
|
+
|
827
|
+
This is an incomplete subsection. I know almost nothing at all about
|
828
|
+
C; kojix2 knows more, so I refer you to the homepage of ruby-libui
|
829
|
+
respectively.
|
830
|
+
|
831
|
+
Most of the code for ruby-libui resides under **ffi.rb**. In August 2021
|
832
|
+
this file contains almost 1000 lines, including newlines. Still quite
|
833
|
+
some code. If you want to look at the raw content, have a look at
|
834
|
+
the following link for **ffi.rb**:
|
835
|
+
|
836
|
+
https://raw.githubusercontent.com/kojix2/LibUI/main/lib/libui/ffi.rb
|
837
|
+
|
838
|
+
The two most important components there, as far as I understand it,
|
839
|
+
are **try_extern** and **structs**.
|
840
|
+
|
841
|
+
For instance:
|
842
|
+
|
843
|
+
try_extern 'void uiOnShouldQuit(int (*f)(void *data), void *data)'
|
844
|
+
|
845
|
+
Control = struct [
|
846
|
+
|
847
|
+
I assume that any support made available for ruby **must** have a
|
848
|
+
corresponding entry in **ffi.rb**. At the least this is how I
|
849
|
+
understood it.
|
850
|
+
|
851
|
+
If it is not in **ffi.rb** then support for that was not (yet) added.
|
852
|
+
|
853
|
+
Individual enum entries can also be seen. For instance, for font-related
|
854
|
+
data the following attributes are in use:
|
855
|
+
|
856
|
+
AttributeTypeFamily = 0
|
857
|
+
AttributeTypeSize = 1
|
858
|
+
AttributeTypeWeight = 2
|
859
|
+
AttributeTypeItalic = 3
|
860
|
+
AttributeTypeStretch = 4
|
861
|
+
AttributeTypeColor = 5
|
862
|
+
AttributeTypeBackground = 6
|
863
|
+
AttributeTypeUnderline = 7
|
864
|
+
AttributeTypeUnderlineColor = 8
|
865
|
+
AttributeTypeFeatures = 9
|
866
|
+
|
867
|
+
You can probably use the rubygems features of comparing old gem
|
868
|
+
releases with one another to see which support has been added to
|
869
|
+
ruby-libui over the past months or so. Most work was probably done
|
870
|
+
in 2020 or even before that (there are some older ruby bindings
|
871
|
+
to libui, but these work differently as kojix2 explained).
|
872
|
+
|
873
|
+
## Limitations of/in LibUI
|
874
|
+
|
875
|
+
LibUI is not perfect - it is missing many things that should work just fine
|
876
|
+
on the main operating systems. On top of that I'd love to support specific
|
877
|
+
features on a given operating system even if it is NOT cross-platform. But
|
878
|
+
this is not possible via LibUI.
|
879
|
+
|
880
|
+
The following subsection mentions a few constraints of LibUI in varying
|
881
|
+
degrees of complexity/importance:
|
882
|
+
|
883
|
+
- No CSS support. I miss this. On ruby-gtk3 this is possible. In LibUI I can't.
|
884
|
+
- Unable to set different fonts for an application other than using FontButton.
|
885
|
+
|
886
|
+
## Structure of the project
|
887
|
+
|
888
|
+
In **September 2021** the libui_paradise project was re-arranged slightly. There
|
889
|
+
is now a dedicated **libui_classes/** directory that "simulates" separate classes.
|
890
|
+
For example, libui_button now resides in **button.rb**. I use the same directory
|
891
|
+
layout in the **gtk_paradise** gem and I think it makes a lot of sense - at the
|
892
|
+
least I can quickly find the code that I may want to modify or extend. If I
|
893
|
+
want to extend buttons, then I modify **buttons.rb**. That's simple, right?
|
894
|
+
|
895
|
+
Another reason why the project was re-structured was so that we can use a
|
896
|
+
**unified DSL** for the GUI elements in the long run.
|
897
|
+
|
898
|
+
For example, code such as the following:
|
899
|
+
|
900
|
+
_ = button
|
901
|
+
_.on_clicked {
|
902
|
+
puts 'Hello world!'
|
903
|
+
}
|
904
|
+
|
905
|
+
Should work on ruby-gtk3, libui and all the other toolkits one day - even on
|
906
|
+
the www. But the different toolkits do not implement the same functionality.
|
907
|
+
Libui only offers a reduced functionality, for instance. Thus, the DSL that
|
908
|
+
we may then use **can only support a subset of functionality**, whereas other
|
909
|
+
toolkits are more useful in this regard. This was an additional reason why files
|
910
|
+
such as button.rb were created - it makes it easier to know which functionality
|
911
|
+
has to be changed in order for libui_paradise to enable such a unified
|
912
|
+
DSL approach. This currently does not yet work fine in 2021, but one day it
|
913
|
+
should work just fine.
|
914
|
+
|
915
|
+
Note that the older l**ibui_paradise gem** will be made available at the
|
916
|
+
least for three months (so until end of December 2021 at the least). It used
|
917
|
+
a different directory layout.
|
918
|
+
|
919
|
+
You may ask why the main module is called **LibuiParadise::Extensions**.
|
920
|
+
Why not modify LibUI directly? After all the gtk_paradise gem does the
|
921
|
+
same, by modifying **module Gtk** directly.
|
922
|
+
|
923
|
+
That is a good question, and the main reason for this is because I was
|
924
|
+
not sure whether I can actually get away with modifying the LibUI
|
925
|
+
namespace directly. Fiddle::Pointer still scares me, so I am experimenting.
|
926
|
+
|
927
|
+
For now I thought it best to create a separate module, that is then included
|
928
|
+
and modified - see the **included hook** that is presently used. This seems
|
929
|
+
to be simpler for the time being. I may plan to change a lot more one day,
|
930
|
+
if I ever manage to find out how to simulate proper subclasses via
|
931
|
+
Fiddle::Pointer ... :)
|
932
|
+
|
933
|
+
--------------------------------------------------------------------------------
|
934
|
+
## SNIPPETS.md
|
935
|
+
|
936
|
+
Next, the content of the file called **SNIPPETS.md** will be shown.
|
937
|
+
|
938
|
+
EMBED_THIS_FILE /home/x/programming/ruby/src/libui_paradise/doc/SNIPPETS.md
|
939
|
+
|
940
|
+
--------------------------------------------------------------------------------
|
941
|
+
|
942
|
+
## Advantages and Disadvantages of the libui project
|
943
|
+
|
944
|
+
It would be unfair to only selectively name advantages but not talk about
|
945
|
+
disadvantages, so this subsection will show some limitations, trade-offs,
|
946
|
+
constraints and opportunities. This is not complete, but it may become
|
947
|
+
somewhat more complete over time. Stay tuned.
|
948
|
+
|
949
|
+
(a) Advantages:
|
950
|
+
|
951
|
+
- Works on windows out-of-the-box after you installed the libui-gem.
|
952
|
+
- Is super-simple to use compared to other toolkits, including ruby-gtk.
|
953
|
+
- Super-simple to build up a prototype for a GUI, buttons that work,
|
954
|
+
spin-boxes, text-views and so forth. Faster than any other toolkit
|
955
|
+
IMO.
|
956
|
+
- Works cross-platform.
|
957
|
+
|
958
|
+
(b) Disadvantage:
|
959
|
+
|
960
|
+
- Limited ability to control the layout and size of widgets.
|
961
|
+
- May look like utter crap ... :-)
|
962
|
+
- Some functionality is missing, such as a scrolled-window for every widget.
|
963
|
+
- No way to use different fonts in the same application and choosing a font
|
964
|
+
is needlessly complicated.
|
965
|
+
|
966
|
+
Some more disadvantages relate to Fiddle::Pointer. You kind of need to
|
967
|
+
know C fairly well as well as the GC in ruby, in order to understand
|
968
|
+
what is going on. Since I don't, I hit a dead end, kind of.
|
969
|
+
|
970
|
+
This is so far in September 2021. Let's see what the future brings.
|
971
|
+
Perhaps other toolkits will learn from libui and implement the good
|
972
|
+
parts for **their own** widget set.
|
973
|
+
|
974
|
+
## LibuiParadise.parse_this_config_file()
|
975
|
+
|
976
|
+
This method can be used to parse a .config file. This file should
|
977
|
+
describe the main window, such as:
|
978
|
+
|
979
|
+
width: 1000
|
980
|
+
height: 150
|
981
|
+
title: Parse Config File Example
|
982
|
+
|
983
|
+
I have been using this in gtk_paradise and I think it may be convenient
|
984
|
+
if you create lots of small windows and widgets that you don't want
|
985
|
+
to hardcode values for directly into the .rb file at hand.
|
986
|
+
|
987
|
+
To create a toplevel window from this use code such as the following:
|
988
|
+
|
989
|
+
use_this_config_file = '023_parse_config_file_example.config'
|
990
|
+
window = LibuiParadise.parse_this_config_file(use_this_config_file)
|
991
|
+
|
992
|
+
In fact, the example **023_parse_config_file_example.rb** shows how
|
993
|
+
this is used. The width of the main window will be 1000 and the
|
994
|
+
height only 150.
|
995
|
+
|
996
|
+
This functionality may be extended in the future. For example, we
|
997
|
+
could enable to automatically parse such a .config file if it
|
998
|
+
exists, thus not even requiring that method call in the future.
|
999
|
+
|
1000
|
+
For now, though, you have to explicitely use that method if you
|
1001
|
+
want to instantiate such a window from a .config file. It will
|
1002
|
+
be evaluated at a later time (past September 2021) how useful this
|
1003
|
+
really is.
|
1004
|
+
|
1005
|
+
## Width and Height of the main window
|
1006
|
+
|
1007
|
+
Different computers have different display values (their monitor).
|
1008
|
+
|
1009
|
+
I use a wide-screen LCD monitor, but I also have smaller laptops,
|
1010
|
+
and I want libui to work there just as well.
|
1011
|
+
|
1012
|
+
The following API can be used to set the width and height of the
|
1013
|
+
main window:
|
1014
|
+
|
1015
|
+
set_height()
|
1016
|
+
set_width()
|
1017
|
+
|
1018
|
+
You can also use something like '95%' as input. In that case the
|
1019
|
+
desired value will be calculated depending on the max-resolution
|
1020
|
+
of the current display. This presently only works on linux; if
|
1021
|
+
someone knows how to make this work on windows and Mac OSX let
|
1022
|
+
me know. (On these systems it will instead default to a hardcoded
|
1023
|
+
value of 1024 for width and 800 for height).
|
1024
|
+
|
1025
|
+
The following example shows how to use a percentage value:
|
1026
|
+
|
1027
|
+
set_height('80%')
|
1028
|
+
|
1029
|
+
## Coloured Text
|
1030
|
+
|
1031
|
+
At this point I only show how this may look on Win7, re-using
|
1032
|
+
the picture the kotlin-libui developers made available:
|
1033
|
+
|
1034
|
+
<img src="https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/drawtext/drawtext-windows7.png" style="margin-left: 2em">
|
1035
|
+
|
1036
|
+
Doesn't look that bad, right? May not be the prettiest GUI of all
|
1037
|
+
times, but it is functional - and simple.
|
1038
|
+
|
1039
|
+
## Status of the libui_paradise project
|
1040
|
+
|
1041
|
+
I am still, as of 2021, experimenting somewhat randomly. While I intend to
|
1042
|
+
improve libui_paradise, it is a hobby project that is not as important
|
1043
|
+
as, say, the gtk_paradise project (which contains custom ruby-gtk
|
1044
|
+
related addons; ruby-gtk has a LOT more functionality than libui has).
|
1045
|
+
|
1046
|
+
I can not promise to work reliably on libui_paradise, but every now and
|
1047
|
+
then, say every some weeks, I will try to add more code to it, in
|
1048
|
+
particular examples and documentation. However had, keep in mind that
|
1049
|
+
the project is not one of my most important projects, so it may not
|
1050
|
+
receive as many updates as other projects. See also the next subsection,
|
1051
|
+
the "Todo List".
|
1052
|
+
|
1053
|
+
## DSLs for libui (in ruby)
|
1054
|
+
|
1055
|
+
kojix2 pointed out that glimmer has support for libui; check it out
|
1056
|
+
here:
|
1057
|
+
|
1058
|
+
https://github.com/AndyObtiva/glimmer-dsl-libui
|
1059
|
+
|
1060
|
+
libui_paradise will support the same syntax (in the long run) as
|
1061
|
+
glimmer does, either directly, or via a module and a way to
|
1062
|
+
require it specifically. But stay tuned for this - right now as
|
1063
|
+
of late 2021 this is not yet guaranteed. (If anyone needs quick
|
1064
|
+
API changes, let me know and I'll change libui_paradise. Other
|
1065
|
+
than that, the libui_paradise project is in a slow maintenance
|
1066
|
+
mode right now, so again, stay tuned. \o/ )
|
1067
|
+
|
1068
|
+
## Todo List and Goals related to libui
|
1069
|
+
|
1070
|
+
Here I will list some todo entries and related goals for libui or the
|
1071
|
+
libui_paradise gem - if anyone finds out how to solve some of these
|
1072
|
+
limitations, you are welcome to share!
|
1073
|
+
|
1074
|
+
- Add more small, **standalone examples** showcasing how to use (and
|
1075
|
+
combine) different functionality, in particular colourized text and use
|
1076
|
+
of (embedded) images if applicable. Ideally we should be able to combine
|
1077
|
+
both freely, if possible.
|
1078
|
+
|
1079
|
+
- Find out how to create "proper" subclasses to Fiddle::Pointer, simulating
|
1080
|
+
a subclass to it.
|
1081
|
+
|
1082
|
+
- Find out how halign and valign work in Libui-Grid. Somehow I can not easily reposition it ...
|
1083
|
+
or perhaps I have been able to, and just have not noticed this (may have to embed one
|
1084
|
+
widget in another widget in order for this to come into effect)
|
1085
|
+
|
1086
|
+
- Find out how to do ad-hoc calls on linux to gtk, so that we can use CSS.
|
1087
|
+
Perhaps some extension mechanism could be used, similar to how ffi works
|
1088
|
+
in general. Unfortunately this probably requires knowledge of C, so this
|
1089
|
+
is an obstacle for me. I should have learned C before ruby ... :P
|
1090
|
+
|
1091
|
+
- Get more people to learn about libui and use them in their projects,
|
1092
|
+
in particular for simple applications. I think this is the most important
|
1093
|
+
goal: we need more people to learn about libui and begin to use it.
|
1094
|
+
Contribute to upstream as well. If we have a sufficiently large user
|
1095
|
+
base then it should be easier to add new possibilities onto libui,
|
1096
|
+
which in turn will "cascade" downwards to all the other bindings
|
1097
|
+
to libui, be it in kotlin, python, ruby and so forth.
|
1098
|
+
|
1099
|
+
## DateTime Widget
|
1100
|
+
|
1101
|
+
Only an image is shown how it may look on windows:
|
1102
|
+
|
1103
|
+
<img src="https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/datetime/datetime-windows7.png" style="margin-left: 2em">
|
1104
|
+
|
1105
|
+
## Password entries in LibUI
|
1106
|
+
|
1107
|
+
If you use the libui_paradise gem then you can create a new password entry
|
1108
|
+
in using any of the following variants:
|
1109
|
+
|
1110
|
+
entry = ui_password_entry
|
1111
|
+
entry = password_entry
|
1112
|
+
|
1113
|
+
For "raw" libui, use this:
|
1114
|
+
|
1115
|
+
LibUI.new_password_entry
|
1116
|
+
|
1117
|
+
## Progress Bars in LibUI
|
1118
|
+
|
1119
|
+
Here an image how this may look:
|
1120
|
+
|
1121
|
+
<img src="https://i.imgur.com/i1i4ppZ.png" style="margin-left: 2em">
|
1122
|
+
|
1123
|
+
## Tables in LibUI
|
1124
|
+
|
1125
|
+
You may be able to create a new table via:
|
1126
|
+
|
1127
|
+
table = LibUI.new_table
|
1128
|
+
|
1129
|
+
model = LibUI.new_table_model(model_handler)
|
1130
|
+
|
1131
|
+
table_params = LibUI::FFI::TableParams.malloc
|
1132
|
+
table_params = Fiddle::RUBY_FREE
|
1133
|
+
table_params.Model = model
|
1134
|
+
table_params.RowBackgroundColorModelColumn = -1
|
1135
|
+
table = LibUI.new_table(table_params)
|
1136
|
+
|
1137
|
+
The table header is an array that contains the following attributes:
|
1138
|
+
|
1139
|
+
1. editable, bool type, the column is whether editable
|
1140
|
+
2. textColor
|
1141
|
+
3. title
|
1142
|
+
4. type, specify value of button, image, imgtext, progress, checkbox, checkboxtext, color, text
|
1143
|
+
|
1144
|
+
Note that this is incomplete; it's a bit complicated.
|
1145
|
+
|
1146
|
+
In the end, this is possible though:
|
1147
|
+
|
1148
|
+
<img src="https://raw.githubusercontent.com/msink/kotlin-libui/master/samples/table/table-windows7.png" style="margin-left: 2em">
|
1149
|
+
|
1150
|
+
## Form example in LibuiParadise
|
1151
|
+
|
1152
|
+
Inspired by **glimmer-libui**, I ported the form example, into
|
1153
|
+
**027_form_example.rb**. Unfortunately it does not look
|
1154
|
+
as good as it does in **glimmer-libui**, and the code I use for
|
1155
|
+
it is too verbose right now.
|
1156
|
+
|
1157
|
+
Still, if you are curious, this is how it looks on icewm
|
1158
|
+
in October 2021:
|
1159
|
+
|
1160
|
+
<img src="https://i.imgur.com/FkU6aWd.png" style="margin-left: 2em">
|
1161
|
+
|
1162
|
+
I may improve this eventually a bit, so that the alignment looks
|
1163
|
+
as good as it does on glimmer-dsl; the code of 27_form_example.rb
|
1164
|
+
may also be cleaned up in the future (the glimmer-libui code
|
1165
|
+
looks better). But for now this is how it is; Andy is very
|
1166
|
+
actively improving **glimmer-libui** right now.
|
1167
|
+
|
1168
|
+
Available "new"-widgets in LibUI:
|
1169
|
+
|
1170
|
+
LibUI.new_area
|
1171
|
+
LibUI.new_attributed_string
|
1172
|
+
LibUI.new_group
|
1173
|
+
LibUI.new_spinbox
|
1174
|
+
LibUI.new_stretch_attribute
|
1175
|
+
LibUI.new_background_attribute
|
1176
|
+
LibUI.new_button # this is a simple button
|
1177
|
+
LibUI.new_checkbox # this is a simple checkbox
|
1178
|
+
LibUI.new_color_attribute
|
1179
|
+
LibUI.new_color_button
|
1180
|
+
LibUI.new_combobox # this is a combobox
|
1181
|
+
LibUI.new_date_picker
|
1182
|
+
LibUI.new_date_time_picker
|
1183
|
+
LibUI.new_editable_combobox
|
1184
|
+
LibUI.new_grid
|
1185
|
+
LibUI.new_horizontal_box
|
1186
|
+
LibUI.new_horizontal_separator # this is a simple horizontal separator
|
1187
|
+
LibUI.new_image # this is a simple image
|
1188
|
+
LibUI.new_italic_attribute # this is basically italic font-style
|
1189
|
+
LibUI.new_label
|
1190
|
+
LibUI.new_tab
|
1191
|
+
LibUI.new_table # this is a simple table
|
1192
|
+
LibUI.new_table_model
|
1193
|
+
LibUI.new_table_value_image
|
1194
|
+
LibUI.new_table_value_int
|
1195
|
+
LibUI.new_table_value_color
|
1196
|
+
LibUI.new_table_value_string
|
1197
|
+
LibUI.new_time_picker
|
1198
|
+
LibUI.new_menu
|
1199
|
+
LibUI.new_multiline_entry # this is a textview
|
1200
|
+
LibUI.new_non_wrapping_multiline_entry
|
1201
|
+
LibUI.new_open_type_features
|
1202
|
+
LibUI.new_password_entry
|
1203
|
+
LibUI.new_underline_attribute
|
1204
|
+
LibUI.new_entry
|
1205
|
+
LibUI.new_progress_bar # this is a progress_bar
|
1206
|
+
LibUI.new_underline_color_attribute
|
1207
|
+
LibUI.new_family_attribute
|
1208
|
+
LibUI.new_radio_buttons
|
1209
|
+
LibUI.new_vertical_box
|
1210
|
+
LibUI.new_features_attribute
|
1211
|
+
LibUI.new_scrolling_area # this is a scrolling area
|
1212
|
+
LibUI.new_vertical_separator
|
1213
|
+
LibUI.new_font_button
|
1214
|
+
LibUI.new_search_entry # this is a search entry
|
1215
|
+
LibUI.new_weight_attribute
|
1216
|
+
LibUI.new_form # this is a form
|
1217
|
+
LibUI.new_size_attribute
|
1218
|
+
LibUI.new_window
|
1219
|
+
LibUI.new_slider
|
1220
|
+
|
1221
|
+
## Links related to libui or libui-based projects
|
1222
|
+
|
1223
|
+
This subsection may contain a few links, in the event that other
|
1224
|
+
people want to see useful entries.
|
1225
|
+
|
1226
|
+
I will try to explain what is to be seen by these various pages.
|
1227
|
+
|
1228
|
+
(1) https://wiki.call-cc.org/eggref/4/libui
|
1229
|
+
|
1230
|
+
This is using chicken-egg scheme for bindings to libui. I like the
|
1231
|
+
simplicity and overview - it's really nice to read and use. I'd
|
1232
|
+
wish we would have this for ruby too. :)
|
1233
|
+
|
1234
|
+
Note that the documentation is outdated as of 2021, though. A fate
|
1235
|
+
shared with a lot of documentation in general out there ...
|
1236
|
+
|
1237
|
+
(2) https://pkg.go.dev/github.com/andlabs/ui
|
1238
|
+
|
1239
|
+
This is andlabs' documentation for libui, from the point of view of
|
1240
|
+
**Go**. It is probably the biggest, most complete documentation for
|
1241
|
+
libui. While it is specific to Go, as it was written by the same
|
1242
|
+
author you can expect the documentation to be quite decent.
|
1243
|
+
|
1244
|
+
(Note that some other bindings contain good documentation too,
|
1245
|
+
such as kotlin libui bindings and others.)
|
1246
|
+
|
1247
|
+
(3) http://api.call-cc.org/4/doc/libui
|
1248
|
+
|
1249
|
+
Similar to the first one, but uses a different layout, which
|
1250
|
+
may be helpful.
|
1251
|
+
|
1252
|
+
ADD_CONTACT_INFORMATION
|