nuklear 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +21 -0
- data/README.md +196 -0
- data/Rakefile +26 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/arial.ttf +0 -0
- data/examples/calculator.rb +102 -0
- data/examples/hello_nuklear.rb +182 -0
- data/examples/lib/opengl_font.rb +32 -0
- data/examples/lib/opengl_init.rb +4 -0
- data/examples/lib/sdl2_init.rb +6 -0
- data/examples/lib/sdl2_input.rb +81 -0
- data/examples/lib/window.rb +47 -0
- data/ext/freetype/extconf.rb +26 -0
- data/ext/nuklear/extconf.rb +14 -0
- data/ext/nuklear/nkrb.c +79 -0
- data/ext/nuklear/nkrb.h +89 -0
- data/ext/nuklear/nkrb_buffer.c +80 -0
- data/ext/nuklear/nkrb_context.c +241 -0
- data/ext/nuklear/nkrb_font.c +80 -0
- data/ext/nuklear/nkrb_renderer.c +114 -0
- data/ext/nuklear/nkrb_style.c +61 -0
- data/ext/nuklear/nkrb_style_color.c +126 -0
- data/ext/nuklear/nkrb_style_image.c +32 -0
- data/ext/nuklear/nkrb_ui.c +32 -0
- data/ext/nuklear/nkrb_ui_builder.c +29 -0
- data/ext/nuklear/nkrb_ui_button.c +55 -0
- data/ext/nuklear/nkrb_ui_color_picker.c +20 -0
- data/ext/nuklear/nkrb_ui_combo.c +73 -0
- data/ext/nuklear/nkrb_ui_container.c +7 -0
- data/ext/nuklear/nkrb_ui_edit_string.c +38 -0
- data/ext/nuklear/nkrb_ui_group.c +27 -0
- data/ext/nuklear/nkrb_ui_label.c +30 -0
- data/ext/nuklear/nkrb_ui_layout.c +125 -0
- data/ext/nuklear/nkrb_ui_menu.c +49 -0
- data/ext/nuklear/nkrb_ui_menu_item.c +30 -0
- data/ext/nuklear/nkrb_ui_menubar.c +18 -0
- data/ext/nuklear/nkrb_ui_popup.c +24 -0
- data/ext/nuklear/nkrb_ui_progress.c +19 -0
- data/ext/nuklear/nkrb_ui_property.c +20 -0
- data/ext/nuklear/nkrb_ui_selectables.c +53 -0
- data/ext/nuklear/nkrb_ui_slider.c +19 -0
- data/ext/nuklear/nkrb_ui_tree.c +29 -0
- data/ext/nuklear/nkrb_ui_widget.c +7 -0
- data/ext/nuklear/nkrb_ui_window.c +43 -0
- data/ext/nuklear/nuklear.h +23378 -0
- data/ext/nuklear_renderer_opengl2/KHR/khrplatform.h +285 -0
- data/ext/nuklear_renderer_opengl2/extconf.rb +13 -0
- data/ext/nuklear_renderer_opengl2/glad.c +1432 -0
- data/ext/nuklear_renderer_opengl2/glad.h +2747 -0
- data/ext/nuklear_renderer_opengl2/nuklear_renderer_opengl2.c +197 -0
- data/ext/nuklear_renderer_opengl4/KHR/khrplatform.h +285 -0
- data/ext/nuklear_renderer_opengl4/extconf.rb +13 -0
- data/ext/nuklear_renderer_opengl4/glad.c +1782 -0
- data/ext/nuklear_renderer_opengl4/glad.h +3687 -0
- data/ext/nuklear_renderer_opengl4/nuklear_renderer_opengl4.c +255 -0
- data/lib/nuklear/context.rb +49 -0
- data/lib/nuklear/dsl.rb +46 -0
- data/lib/nuklear/event_buffer.rb +23 -0
- data/lib/nuklear/renderer/opengl24.rb +13 -0
- data/lib/nuklear/renderer.rb +108 -0
- data/lib/nuklear/style/color.rb +24 -0
- data/lib/nuklear/style/image.rb +9 -0
- data/lib/nuklear/style.rb +8 -0
- data/lib/nuklear/test_case.rb +30 -0
- data/lib/nuklear/ui/base.rb +34 -0
- data/lib/nuklear/ui/button.rb +77 -0
- data/lib/nuklear/ui/checkbox.rb +39 -0
- data/lib/nuklear/ui/col.rb +21 -0
- data/lib/nuklear/ui/color_picker.rb +31 -0
- data/lib/nuklear/ui/combo_box.rb +42 -0
- data/lib/nuklear/ui/container.rb +80 -0
- data/lib/nuklear/ui/edit_string.rb +48 -0
- data/lib/nuklear/ui/enableable.rb +29 -0
- data/lib/nuklear/ui/events.rb +23 -0
- data/lib/nuklear/ui/group.rb +31 -0
- data/lib/nuklear/ui/label.rb +21 -0
- data/lib/nuklear/ui/menu.rb +43 -0
- data/lib/nuklear/ui/menu_bar.rb +19 -0
- data/lib/nuklear/ui/menu_item.rb +34 -0
- data/lib/nuklear/ui/option.rb +17 -0
- data/lib/nuklear/ui/option_group.rb +22 -0
- data/lib/nuklear/ui/popup.rb +37 -0
- data/lib/nuklear/ui/progress.rb +33 -0
- data/lib/nuklear/ui/property.rb +28 -0
- data/lib/nuklear/ui/row.rb +28 -0
- data/lib/nuklear/ui/select_list.rb +31 -0
- data/lib/nuklear/ui/selectable.rb +21 -0
- data/lib/nuklear/ui/slider.rb +26 -0
- data/lib/nuklear/ui/text_align.rb +14 -0
- data/lib/nuklear/ui/tree.rb +62 -0
- data/lib/nuklear/ui/window.rb +175 -0
- data/lib/nuklear/ui.rb +33 -0
- data/lib/nuklear/version.rb +3 -0
- data/lib/nuklear.rb +26 -0
- data/nuklear.gemspec +41 -0
- metadata +233 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 00d829f1e7f4d4d305a18e1d831df3cd95874224581986977a89fd2eb114da0f
|
|
4
|
+
data.tar.gz: 45da4ef0e277ca42d642919a06c8086952c695a139b45265df6d5b7ceb4d5aaa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: baa5798e57b4f1765b4e819ee7dac4db9aa40e172f44fd48c74ff6b6942bc8c0d5afdc55cc137aeb400b4c48f51cd5286000b4b849505e11b94f2de2e8e9ec43
|
|
7
|
+
data.tar.gz: f37d1e63dcb902f2752c21e37d3ceaebccb0a2b5b9d50d615925049010dc2eedf3c726da9edc0687a63ba9ec651ffcd03cbc052cd0ea16c1b38e28275aa9e777
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
nuklear (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
minitest (5.15.0)
|
|
10
|
+
opengl-bindings (1.6.12)
|
|
11
|
+
rake (13.0.6)
|
|
12
|
+
rake-compiler (1.1.9)
|
|
13
|
+
rake
|
|
14
|
+
ruby-sdl2 (0.3.5)
|
|
15
|
+
|
|
16
|
+
PLATFORMS
|
|
17
|
+
ruby
|
|
18
|
+
|
|
19
|
+
DEPENDENCIES
|
|
20
|
+
bundler (>= 2.0)
|
|
21
|
+
minitest (>= 5.0)
|
|
22
|
+
nuklear!
|
|
23
|
+
opengl-bindings
|
|
24
|
+
rake (>= 10.0)
|
|
25
|
+
rake-compiler
|
|
26
|
+
ruby-sdl2
|
|
27
|
+
|
|
28
|
+
BUNDLED WITH
|
|
29
|
+
2.2.3
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Colin MacKenzie IV
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Nuklear
|
|
2
|
+
|
|
3
|
+
Ruby bindings for [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear).
|
|
4
|
+
|
|
5
|
+
Here is the description from the Nuklear project:
|
|
6
|
+
|
|
7
|
+
> This is a minimal-state, immediate-mode graphical user interface toolkit
|
|
8
|
+
> written in ANSI C and licensed under public domain. It was designed as a
|
|
9
|
+
> simple embeddable user interface for application and does not have any
|
|
10
|
+
> dependencies, a default render backend or OS window/input handling but
|
|
11
|
+
> instead provides a highly modular, library-based approach, with simple
|
|
12
|
+
> input state for input and draw commands describing primitive shapes as
|
|
13
|
+
> output. So instead of providing a layered library that tries to abstract
|
|
14
|
+
> over a number of platform and render backends, it focuses only on the actual
|
|
15
|
+
> UI.
|
|
16
|
+
|
|
17
|
+
This project implements a set of Ruby classes which wrap the Nuklear API. It
|
|
18
|
+
also provides two sample renderers (OpenGL 2 and OpenGL 4).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add this line to your application's Gemfile:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem 'nuklear'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
And then execute:
|
|
30
|
+
|
|
31
|
+
$ bundle
|
|
32
|
+
|
|
33
|
+
Or install it yourself as:
|
|
34
|
+
|
|
35
|
+
$ gem install nuklear
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Renderers
|
|
39
|
+
|
|
40
|
+
The base class `Nuklear::Renderer` is essentially a headless renderer. It
|
|
41
|
+
implements all necessary functionality to serve as a renderer for Nuklear,
|
|
42
|
+
except the actual drawing, and is also intended to be subclassed for a custom
|
|
43
|
+
renderer which actually draws something. The two bundled OpenGL renderers
|
|
44
|
+
(`Nuklear::Renderer::OpenGL2` and `Nuklear::Renderer::OpenGL4`) are examples
|
|
45
|
+
of this.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
The following examples are to help introduce you to how to use Nuklear, and
|
|
51
|
+
to inform you as to how Nuklear fits into the larger design of a graphical
|
|
52
|
+
application. They are not complete examples. For complete, functional
|
|
53
|
+
examples, see the files in /examples/.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Initialization
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
# Nuklear will load the font files for us, and will generate a font atlas
|
|
60
|
+
# image. Then it will yield the width, height and pixel data of that image
|
|
61
|
+
# to our block. Typically we would use this information to generate a
|
|
62
|
+
# texture for our preferred rendering engine (OpenGL, Vulkan, etc.). Once
|
|
63
|
+
# we have a handle, we pass that handle back to Nuklear as the result of
|
|
64
|
+
# the block. Here we just use `0`. Nuklear will hold on to the handle,
|
|
65
|
+
# and it will be passed back to us as part of draw calls involving the
|
|
66
|
+
#font.
|
|
67
|
+
font = Nuklear::Font.new("arial.ttf", 12) { |w, h, data| 0 }
|
|
68
|
+
|
|
69
|
+
# Once we have our font, we can create a Nuklear context.
|
|
70
|
+
ctx = Nuklear::Context.new(font)
|
|
71
|
+
|
|
72
|
+
# The context requires a renderer. We can pass it an instance of
|
|
73
|
+
# Nuklear::Renderer, but this will not actually draw anything.
|
|
74
|
+
# Nuklear::Renderer is great for unit testing and as a base class for us
|
|
75
|
+
# to actually implement our real renderer on top of. Here, we'll use the
|
|
76
|
+
# bundled OpenGL 2 renderer.
|
|
77
|
+
require 'nuklear/nuklear_renderer_opengl2'
|
|
78
|
+
ctx.renderer = Nuklear::Renderer::OpenGL2.new(ctx)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### With DSL
|
|
82
|
+
|
|
83
|
+
For convenience, a DSL is provided. It is particularly useful for building
|
|
84
|
+
complex, mostly static interfaces as it removes a lot of the repetition that
|
|
85
|
+
would come from using the primary interface. Here is a trivial example:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
ctx.dsl do
|
|
89
|
+
w = window "Hello Nuklear", left: 10, top: 10, width: 100, height: 100 do
|
|
90
|
+
layout_row_dynamic 35, 2
|
|
91
|
+
button "Click me" do
|
|
92
|
+
puts "Ouch!"
|
|
93
|
+
w.close # hide the window
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
See `/examples/calculator.rb` for a more complete demonstration of the DSL.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Without DSL
|
|
103
|
+
|
|
104
|
+
You can opt not to use the DSL, and instantiate the UI widgets directly. This
|
|
105
|
+
is straightforward, but verbose. It can be helpful when you need to
|
|
106
|
+
programmatically build an interface that doesn't need or desire a lot of
|
|
107
|
+
syntactic sugar. For example, the DSL might actively hinder you if you were
|
|
108
|
+
building an interface by parsing a YAML or XML file. Here is how we would
|
|
109
|
+
build the same window as above without use of the DSL:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
# create the Nuklear window
|
|
113
|
+
w = Nuklear::UI::Window.new "Hello Nuklear",
|
|
114
|
+
left: 10,
|
|
115
|
+
top: 10,
|
|
116
|
+
width: 100,
|
|
117
|
+
height: 100
|
|
118
|
+
|
|
119
|
+
# Set up the window layout
|
|
120
|
+
w.layout_row_dynamic 35, 2
|
|
121
|
+
|
|
122
|
+
# Add the button to the window
|
|
123
|
+
w << Nuklear::UI::Button.new "Click me" do
|
|
124
|
+
puts "Ouch!"
|
|
125
|
+
w.close # hide the window
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Add the window to the context
|
|
129
|
+
ctx << w
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
See `/examples/hello_nuklear.rb` for a more complete demonstration without the
|
|
133
|
+
DSL.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### Main Loop
|
|
137
|
+
|
|
138
|
+
Since Nuklear is backend-agnostic, you must do the backend stuff yourself. In
|
|
139
|
+
all of the examples, you'll find that we use SDL2 for the window management
|
|
140
|
+
and event processing, and OpenGL for the actual drawing. You may use whatever
|
|
141
|
+
mechanisms you want, including none. (It's quite useful for unit testing to
|
|
142
|
+
just use the Nuklear::Renderer base class for "drawing" and to
|
|
143
|
+
programmatically deliver only specific window events to Nuklear.)
|
|
144
|
+
|
|
145
|
+
The event processing loop can be a bit verbose, depending on how many events
|
|
146
|
+
you want to respond to, so we'll just show some snippets here. You can find a
|
|
147
|
+
more complete example in `/examples/hello_nuklear.rb`.
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# Initialize the viewport (OpenGL)
|
|
151
|
+
glViewport(0, 0, *window.gl_drawable_size)
|
|
152
|
+
glClearColor(0, 0, 0, 0)
|
|
153
|
+
while true
|
|
154
|
+
# New frame: Clear the screen (OpenGL)
|
|
155
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
156
|
+
|
|
157
|
+
# Process window, mouse, keyboard, etc events (SDL2)
|
|
158
|
+
while event = ::SDL2::Event.poll
|
|
159
|
+
case event
|
|
160
|
+
when SDL2::Event::Quit then exit
|
|
161
|
+
# ...
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Update the Nuklear context. This will generate/update the command buffer
|
|
165
|
+
# in preparation for rendering, then pass that command buffer to our
|
|
166
|
+
# renderer.
|
|
167
|
+
ctx.tick
|
|
168
|
+
|
|
169
|
+
# Show the rendered frame. (OpenGL)
|
|
170
|
+
window.gl_swap
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then,
|
|
178
|
+
run `rake test` to run the tests. You can also run `bin/console` for an
|
|
179
|
+
interactive prompt that will allow you to experiment.
|
|
180
|
+
|
|
181
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
182
|
+
To release a new version, update the version number in `version.rb`, and then
|
|
183
|
+
run `bundle exec rake release`, which will create a git tag for the version,
|
|
184
|
+
push git commits and tags, and push the `.gem` file to
|
|
185
|
+
[rubygems.org](https://rubygems.org).
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
191
|
+
https://github.com/[USERNAME]/nuklear.
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
The gem is available as open source under the terms of the
|
|
196
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
|
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
|
5
|
+
t.libs << "test"
|
|
6
|
+
t.libs << "lib"
|
|
7
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require "rake/extensiontask"
|
|
11
|
+
|
|
12
|
+
task :build => :compile
|
|
13
|
+
|
|
14
|
+
Rake::ExtensionTask.new("nuklear") do |ext|
|
|
15
|
+
ext.lib_dir = "lib/nuklear"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Rake::ExtensionTask.new("nuklear_renderer_opengl2") do |ext|
|
|
19
|
+
ext.lib_dir = "lib/nuklear"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Rake::ExtensionTask.new("nuklear_renderer_opengl4") do |ext|
|
|
23
|
+
ext.lib_dir = "lib/nuklear"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
task :default => [:clobber, :compile, :test]
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "nuklear"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/examples/arial.ttf
ADDED
|
Binary file
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This example is based loosely upon:
|
|
4
|
+
# https://github.com/Immediate-Mode-UI/Nuklear/blob/master/demo/calculator.c
|
|
5
|
+
#
|
|
6
|
+
# This demonstrates using the Nuklear DSL to build and maintain a simple but
|
|
7
|
+
# functional calculator. In order to show you only the most relevant
|
|
8
|
+
# information, much of the set-up code has been moved to /examples/lib/ and
|
|
9
|
+
# this file focuses mainly on the DSL. If you are more interested in the
|
|
10
|
+
# set-up code and event loop, you will find that the files in /examples/lib/
|
|
11
|
+
# are quite similar to what appears in /examples/hello_nuklear.rb.
|
|
12
|
+
#
|
|
13
|
+
require 'bundler/setup'
|
|
14
|
+
require 'nuklear'
|
|
15
|
+
require_relative 'lib/sdl2_init'
|
|
16
|
+
require_relative 'lib/sdl2_input'
|
|
17
|
+
require_relative 'lib/opengl_init'
|
|
18
|
+
require_relative 'lib/opengl_font'
|
|
19
|
+
require_relative 'lib/window'
|
|
20
|
+
|
|
21
|
+
class Calculator
|
|
22
|
+
attr_reader :ctx, :window
|
|
23
|
+
|
|
24
|
+
def initialize(hidden: false)
|
|
25
|
+
@window = Examples::Window.new "Calculator Example", hidden: hidden
|
|
26
|
+
font = Examples::OpenGLFont.new File.expand_path("arial.ttf", __dir__)
|
|
27
|
+
@ctx = Nuklear::Context.new font.nuklear_handle
|
|
28
|
+
@window.nuklear_context = @ctx
|
|
29
|
+
|
|
30
|
+
numbers = '789456123'
|
|
31
|
+
ops = '+-*/'
|
|
32
|
+
operands = [0, 0]
|
|
33
|
+
current = 0
|
|
34
|
+
set = op = nil
|
|
35
|
+
|
|
36
|
+
@ctx.dsl do
|
|
37
|
+
window("Hello Nuklear", left: 10, top: 10, width: 180, height: 250,
|
|
38
|
+
border: true, no_scrollbar: true, movable: true) do
|
|
39
|
+
layout_row_dynamic 35, 1
|
|
40
|
+
label = edit_string text: "0.0", flags: :simple, filter: :float, max_length: 255
|
|
41
|
+
|
|
42
|
+
layout_row_dynamic 35, 4
|
|
43
|
+
update = proc { label.text = '%.2f' % operands[current] }
|
|
44
|
+
solver = proc do
|
|
45
|
+
# operands[0] = operands[0] + operands[1]
|
|
46
|
+
operands[0] = operands[0].send(op, operands[1])
|
|
47
|
+
label.text = '%.2f' % operands[0]
|
|
48
|
+
current = 1
|
|
49
|
+
operands[1] = 0
|
|
50
|
+
set = true
|
|
51
|
+
end
|
|
52
|
+
16.times do |i|
|
|
53
|
+
if i >= 12 && i < 15
|
|
54
|
+
next if i > 12
|
|
55
|
+
button("C") { operands = [0, 0]; current = 0; op = nil; update.call }
|
|
56
|
+
button("0") { operands[current] *= 10; update.call }
|
|
57
|
+
button("=") { solver.call; op = nil }
|
|
58
|
+
elsif (i + 1) % 4 > 0
|
|
59
|
+
n = numbers[(i/4)*3+i%4]
|
|
60
|
+
button(n) do
|
|
61
|
+
operands[current] = operands[current] * 10 + n.to_i
|
|
62
|
+
set = nil
|
|
63
|
+
update.call
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
n = ops[i/4]
|
|
67
|
+
button(n) do
|
|
68
|
+
if !set
|
|
69
|
+
if current != 1
|
|
70
|
+
current = 1
|
|
71
|
+
update.call
|
|
72
|
+
else
|
|
73
|
+
solver.call
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
op = ops[i/4]
|
|
77
|
+
set = true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def tick
|
|
86
|
+
@window.frame do
|
|
87
|
+
@ctx.tick
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def close
|
|
92
|
+
@window.close
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if $0 == __FILE__
|
|
97
|
+
calculator = Calculator.new
|
|
98
|
+
while true
|
|
99
|
+
# process window events and render any display changes
|
|
100
|
+
calculator.tick
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This example is completely self-contained (the files in /examples/lib/ are
|
|
4
|
+
# not used), so it makes a good "holistic" reference. It's a little on the
|
|
5
|
+
# large side, mainly because of the SDL2 event loop as interesting events have
|
|
6
|
+
# to be delegated into Nuklear so that, for example, button clicks actually
|
|
7
|
+
# do something.
|
|
8
|
+
#
|
|
9
|
+
# This example also eschews the Nuklear DSL, instead preferring to instantiate
|
|
10
|
+
# the UI widgets directly. Essentially, this shows you what is happening
|
|
11
|
+
# within the DSL, and it can be a useful reference if you're in a situation
|
|
12
|
+
# where the DSL is cumbersome to use. That said, it's not nearly as pretty
|
|
13
|
+
# or intuitive as using the DSL would be.
|
|
14
|
+
#
|
|
15
|
+
require 'bundler/setup'
|
|
16
|
+
require 'sdl2'
|
|
17
|
+
require 'nuklear'
|
|
18
|
+
require 'opengl'
|
|
19
|
+
include OpenGL
|
|
20
|
+
OpenGL.load_lib()
|
|
21
|
+
|
|
22
|
+
module SDL2::Window::Flags
|
|
23
|
+
# Shim: Older versions of SDL2 for Ruby didn't define this flag.
|
|
24
|
+
ALLOW_HIGHDPI = 0x00002000 unless defined?(SDL2::Window::Flags::ALLOW_HIGHDPI)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Initialize SDL2 and OpenGL.
|
|
28
|
+
SDL2.init(SDL2::INIT_EVERYTHING)
|
|
29
|
+
SDL2::GL.set_attribute(SDL2::GL::ACCELERATED_VISUAL, 1)
|
|
30
|
+
window = SDL2::Window.create "Nuklear", 0, 0, 640, 480,
|
|
31
|
+
SDL2::Window::Flags::OPENGL |
|
|
32
|
+
SDL2::Window::Flags::ALLOW_HIGHDPI |
|
|
33
|
+
SDL2::Window::Flags::RESIZABLE
|
|
34
|
+
@gl = SDL2::GL::Context.create(window)
|
|
35
|
+
|
|
36
|
+
# When Nuklear loads the font file it will yield to us the width, height
|
|
37
|
+
# and baked font atlas image data. We must then tell OpenGL to load that
|
|
38
|
+
# image data into a texture ID, and then pass the OpenGL texture ID back into
|
|
39
|
+
# Nuklear for later reference.
|
|
40
|
+
font = Nuklear::Font.new(File.expand_path("arial.ttf", __dir__), 14) do |w, h, data|
|
|
41
|
+
# give the image data to OpenGL
|
|
42
|
+
tex_names_buf = ' ' * 8
|
|
43
|
+
glGenTextures(1, tex_names_buf)
|
|
44
|
+
texture_id = tex_names_buf.unpack('L1')[0]
|
|
45
|
+
glBindTexture(GL_TEXTURE_2D, texture_id)
|
|
46
|
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
|
|
47
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
|
48
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
|
49
|
+
# give the GL texture ID to Nuklear
|
|
50
|
+
texture_id
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
ctx = Nuklear::Context.new(font)
|
|
54
|
+
|
|
55
|
+
# We'll use the OpenGL 2 renderer for Nuklear. Notice that we must tell the
|
|
56
|
+
# renderer the size of the window and the size of the drawing surface, which
|
|
57
|
+
# aren't always the same thing.
|
|
58
|
+
require 'nuklear/nuklear_renderer_opengl2'
|
|
59
|
+
ctx.renderer = Nuklear::Renderer::OpenGL2.new(ctx)
|
|
60
|
+
ctx.renderer.window_size = window.size
|
|
61
|
+
ctx.renderer.drawable_size = window.gl_drawable_size
|
|
62
|
+
|
|
63
|
+
# We can now build our Nuklear UI. Let's create a window, then add a few
|
|
64
|
+
# labels and a button to it.
|
|
65
|
+
@window = Nuklear::UI::Window.new("Hello Nuklear",
|
|
66
|
+
left: 60, top: 60, width: 300, height: 200,
|
|
67
|
+
border: true, scalable: true, movable: true, minimizable: true)
|
|
68
|
+
@window.layout_row_dynamic 35, 2
|
|
69
|
+
@window << Nuklear::UI::Label.new("This is a label")
|
|
70
|
+
@window << Nuklear::UI::Button.new("This is a button")
|
|
71
|
+
@window << Nuklear::UI::Label.new("Frame number:")
|
|
72
|
+
@window << @frame_num_label = Nuklear::UI::Label.new("0")
|
|
73
|
+
# Let's also add a large, empty container to the window. This forces Nuklear
|
|
74
|
+
# to add a scrollbar to the window.
|
|
75
|
+
@window.layout_row_dynamic 200, 2
|
|
76
|
+
container = Nuklear::UI::Group.new
|
|
77
|
+
@window << container
|
|
78
|
+
|
|
79
|
+
# Finally, add the window to the context so that Nuklear will render it. We
|
|
80
|
+
# can add any number of windows.
|
|
81
|
+
ctx << @window
|
|
82
|
+
|
|
83
|
+
# Now for the main event loop. This loop is almost entirely dedicated to event
|
|
84
|
+
# processing. Below the event processing, we'll deal with Nuklear.
|
|
85
|
+
@frame_count = 0
|
|
86
|
+
glViewport(0, 0, *window.gl_drawable_size)
|
|
87
|
+
glClearColor(0, 0, 0, 0)
|
|
88
|
+
@last_tick_time = Time.now
|
|
89
|
+
while true
|
|
90
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
91
|
+
|
|
92
|
+
while event = ::SDL2::Event.poll
|
|
93
|
+
case event
|
|
94
|
+
# TODO touch events
|
|
95
|
+
# when SDL2::Event::FingerMotion
|
|
96
|
+
# when SDL2::Event::FingerDown
|
|
97
|
+
# when SDL2::Event::FingerUp
|
|
98
|
+
when ::SDL2::Event::TextInput then ctx.trigger(:glyph, event.text)
|
|
99
|
+
when ::SDL2::Event::MouseMotion then ctx.trigger(:motion, event.x, event.y, event.xrel, event.yrel)
|
|
100
|
+
when ::SDL2::Event::MouseWheel then ctx.trigger(:scroll, event.x, event.y)
|
|
101
|
+
when ::SDL2::Event::MouseButtonDown, ::SDL2::Event::MouseButtonUp
|
|
102
|
+
is_down = event.kind_of?(::SDL2::Event::MouseButtonDown)
|
|
103
|
+
if event.button == 1 and event.clicks > 1
|
|
104
|
+
ctx.trigger(:button, :double, event.x, event.y, is_down)
|
|
105
|
+
else
|
|
106
|
+
case event.button
|
|
107
|
+
# SDL_BUTTON_LEFT seems to be not defined
|
|
108
|
+
when 1 then ctx.trigger(:button, :left, event.x, event.y, is_down)
|
|
109
|
+
when 2 then ctx.trigger(:button, :middle, event.x, event.y, is_down)
|
|
110
|
+
when 3 then ctx.trigger(:button, :right, event.x, event.y, is_down)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
when ::SDL2::Event::Window
|
|
114
|
+
case event.event
|
|
115
|
+
when ::SDL2::Event::Window::FOCUS_GAINED then @focused = true
|
|
116
|
+
when ::SDL2::Event::Window::FOCUS_LOST then @focused = false
|
|
117
|
+
end
|
|
118
|
+
when ::SDL2::Event::KeyDown, ::SDL2::Event::KeyUp
|
|
119
|
+
is_down = event.kind_of?(::SDL2::Event::KeyDown)
|
|
120
|
+
case event.sym
|
|
121
|
+
when ::SDL2::Key::LSHIFT, ::SDL2::Key::RSHIFT then ctx.trigger(:key, :shift, is_down)
|
|
122
|
+
when ::SDL2::Key::DELETE then ctx.trigger(:key, :del, is_down)
|
|
123
|
+
when ::SDL2::Key::RETURN then ctx.trigger(:key, :enter, is_down)
|
|
124
|
+
when ::SDL2::Key::TAB then ctx.trigger(:key, :tab, is_down)
|
|
125
|
+
when ::SDL2::Key::BACKSPACE then ctx.trigger(:key, :backspace, is_down)
|
|
126
|
+
when ::SDL2::Key::HOME then ctx.trigger(:key, :text_start, is_down)
|
|
127
|
+
ctx.trigger(:key, :scroll_start, is_down)
|
|
128
|
+
when ::SDL2::Key::END then ctx.trigger(:key, :text_end, is_down)
|
|
129
|
+
ctx.trigger(:key, :scroll_end, is_down)
|
|
130
|
+
when ::SDL2::Key::PAGEDOWN then ctx.trigger(:key, :scroll_down, is_down)
|
|
131
|
+
when ::SDL2::Key::PAGEUP then ctx.trigger(:key, :scroll_up, is_down)
|
|
132
|
+
when ::SDL2::Key::Z then ctx.trigger(:key, :text_undo, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
133
|
+
when ::SDL2::Key::R then ctx.trigger(:key, :text_redo, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
134
|
+
when ::SDL2::Key::C then ctx.trigger(:key, :copy, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
135
|
+
when ::SDL2::Key::V then ctx.trigger(:key, :paste, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
136
|
+
when ::SDL2::Key::X then ctx.trigger(:key, :cut, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
137
|
+
when ::SDL2::Key::B then ctx.trigger(:key, :text_line_start, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
138
|
+
when ::SDL2::Key::E then ctx.trigger(:key, :text_line_end, is_down && (event.mod & ::SDL2::Key::Mod::CTRL > 0))
|
|
139
|
+
when ::SDL2::Key::UP then ctx.trigger(:key, :up, is_down)
|
|
140
|
+
when ::SDL2::Key::DOWN then ctx.trigger(:key, :down, is_down)
|
|
141
|
+
when ::SDL2::Key::LEFT
|
|
142
|
+
if event.mod & ::SDL2::Key::Mod::CTRL > 0 then ctx.trigger(:key, :text_word_left, is_down)
|
|
143
|
+
else ctx.trigger(:key, :left, is_down)
|
|
144
|
+
end
|
|
145
|
+
when ::SDL2::Key::RIGHT
|
|
146
|
+
if event.mod & ::SDL2::Key::Mod::CTRL > 0 then ctx.trigger(:key, :text_word_right, is_down)
|
|
147
|
+
else ctx.trigger(:key, :right, is_down)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
when SDL2::Event::Quit then exit
|
|
152
|
+
when SDL2::Event::KeyDown
|
|
153
|
+
case event.sym
|
|
154
|
+
when SDL2::Key::C
|
|
155
|
+
if (event.mod & SDL2::Key::Mod::CTRL) > 0
|
|
156
|
+
exit
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Track the number of frames and calculate the amount of time that has
|
|
163
|
+
# elapsed between the last frame and this one.
|
|
164
|
+
@frame_count += 1
|
|
165
|
+
time = Time.now
|
|
166
|
+
delta ||= begin
|
|
167
|
+
delta = time - @last_tick_time
|
|
168
|
+
end
|
|
169
|
+
@last_tick_time = time
|
|
170
|
+
|
|
171
|
+
# Update the frame counter label. The next time Nuklear renders it, the
|
|
172
|
+
# label will contain the updated text.
|
|
173
|
+
@frame_num_label.text = @frame_count.to_s
|
|
174
|
+
|
|
175
|
+
# Update the Nuklear context. This will generate/update the command buffer
|
|
176
|
+
# in preparation for rendering, then pass that command buffer to our
|
|
177
|
+
# renderer.
|
|
178
|
+
ctx.tick
|
|
179
|
+
|
|
180
|
+
# Show the rendered frame.
|
|
181
|
+
window.gl_swap
|
|
182
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# This class facilitates rendering text with Nuklear and presenting it using
|
|
2
|
+
# OpenGL. It is part of the nuklear-ruby examples.
|
|
3
|
+
module Examples
|
|
4
|
+
class OpenGLFont
|
|
5
|
+
attr_reader :path
|
|
6
|
+
|
|
7
|
+
def initialize(path, size = 12)
|
|
8
|
+
@path = path
|
|
9
|
+
@size = size
|
|
10
|
+
@texture_id = nil
|
|
11
|
+
@nuklear_handle = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def texture_id
|
|
15
|
+
@texture_id ||= begin
|
|
16
|
+
tex_names_buf = ' ' * 8
|
|
17
|
+
glGenTextures(1, tex_names_buf)
|
|
18
|
+
tex_names_buf.unpack('L1')[0]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def nuklear_handle
|
|
23
|
+
@nuklear_handle ||= Nuklear::Font.new(path, @size) do |w, h, data|
|
|
24
|
+
glBindTexture(GL_TEXTURE_2D, texture_id)
|
|
25
|
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
|
|
26
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
|
27
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
|
28
|
+
texture_id
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|