nuklear 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|