Module: Clogs::UI
- Defined in:
- lib/clogs/ui.rb
Overview
Thin, hand-rolled conveniences over the raw libui FFI bindings.
Two things make raw libui painful from Ruby and both are handled here:
- Every callback handed to C must be a Fiddle::Closure that outlives the C-side registration. Ruby will happily collect one that is still installed, and libui will then jump into freed memory. UI.callback keeps a permanent reference.
- Structs must be malloc'd and marked with a free function, and several of them (brushes, stroke params, font descriptors) are needed on every single paint. Allocating them per-paint is measurable, so the hot ones are pooled.
Constant Summary collapse
- L =
::LibUI
- WINDING =
Fill modes
0- ALTERNATE =
1- CAP_FLAT =
Line caps / joins
0- CAP_ROUND =
1- CAP_SQUARE =
2- JOIN_MITER =
0- JOIN_ROUND =
1- JOIN_BEVEL =
2- BRUSH_SOLID =
0- BRUSH_LINEAR_GRADIENT =
1- BRUSH_RADIAL_GRADIENT =
2- WEIGHT_NORMAL =
Text weights/italics/stretches we actually use
400- WEIGHT_BOLD =
700- ITALIC_NORMAL =
0- ITALIC_ITALIC =
1- STRETCH_NORMAL =
4- EXT_KEYS =
uiExtKey values, from ui.h. libui reports these separately from
Key. { 1 => :escape, 2 => :insert, 3 => :delete, 4 => :home, 5 => :end, 6 => :page_up, 7 => :page_down, 8 => :up, 9 => :down, 10 => :left, 11 => :right, 12 => :f1, 13 => :f2, 14 => :f3, 15 => :f4, 16 => :f5, 17 => :f6, 18 => :f7, 19 => :f8, 20 => :f9, 21 => :f10, 22 => :f11, 23 => :f12 }.freeze
- MOD_CTRL =
1 << 0
- MOD_ALT =
1 << 1
- MOD_SHIFT =
1 << 2
- MOD_SUPER =
1 << 3
Class Method Summary collapse
-
.callback(return_type, arg_types, &block) ⇒ Object
Closures handed to C live forever.
-
.draw_image? ⇒ Boolean
True if this libui build can blit a uiImage into a draw context.
- .font_descriptor(family, size, weight: WEIGHT_NORMAL, italic: ITALIC_NORMAL) ⇒ Object
-
.gradient_brush(type, from, to, stops, outer_radius: 0) ⇒ Object
A linear or radial gradient brush.
- .malloc(struct_class) ⇒ Object
-
.solid_brush(color) ⇒ Object
A solid uiDrawBrush.
- .stroke_params(thickness, cap: CAP_FLAT, join: JOIN_MITER, dashes: nil) ⇒ Object
-
.text_extents(layout) ⇒ Object
uiDrawTextLayoutExtents writes through two double pointers.
Class Method Details
.callback(return_type, arg_types, &block) ⇒ Object
Closures handed to C live forever. There are a bounded number of them (a handful per window plus one per timer) so this does not grow without bound in practice.
62 63 64 65 66 |
# File 'lib/clogs/ui.rb', line 62 def callback(return_type, arg_types, &block) closure = Fiddle::Closure::BlockCaller.new(return_type, arg_types, &block) (@callbacks ||= []) << closure closure end |
.draw_image? ⇒ Boolean
True if this libui build can blit a uiImage into a draw context. Stock libui-ng cannot; see docs/libui_shoes_coverage.md.
150 151 152 153 154 |
# File 'lib/clogs/ui.rb', line 150 def draw_image? return @draw_image unless @draw_image.nil? @draw_image = L.respond_to?(:draw_image) end |
.font_descriptor(family, size, weight: WEIGHT_NORMAL, italic: ITALIC_NORMAL) ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/clogs/ui.rb', line 127 def font_descriptor(family, size, weight: WEIGHT_NORMAL, italic: ITALIC_NORMAL) fd = malloc(L::FFI::FontDescriptor) fd.Family = family fd.Size = size.to_f fd.Weight = weight fd.Italic = italic fd.Stretch = STRETCH_NORMAL # Fiddle copies the string into the struct but does not own it; keep the # Ruby string alive so the char* stays valid. fd.instance_variable_set(:@clogs_family, family) fd end |
.gradient_brush(type, from, to, stops, outer_radius: 0) ⇒ Object
A linear or radial gradient brush. stops is [[pos, [r,g,b,a]], ...].
The Stops array must stay alive as long as the brush does, so it is stashed on the brush object; Ruby's GC then keeps them together.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/clogs/ui.rb', line 90 def gradient_brush(type, from, to, stops, outer_radius: 0) b = malloc(L::FFI::DrawBrush) b.Type = type b.X0, b.Y0 = from b.X1, b.Y1 = to b.OuterRadius = outer_radius buf = Fiddle::Pointer.malloc(stops.size * 40, Fiddle::RUBY_FREE) stops.each_with_index do |(pos, color), i| r, g, bl, a = color buf[i * 40, 40] = [pos, r / 255.0, g / 255.0, bl / 255.0, (a || 255) / 255.0].pack("d5") end b.Stops = buf b.NumStops = stops.size b.instance_variable_set(:@clogs_stops, buf) b end |
.malloc(struct_class) ⇒ Object
68 69 70 71 72 |
# File 'lib/clogs/ui.rb', line 68 def malloc(struct_class) s = struct_class.malloc s.to_ptr.free = Fiddle::RUBY_FREE s end |
.solid_brush(color) ⇒ Object
A solid uiDrawBrush. Colors arrive as Shoes [r, g, b, a] 0-255 arrays.
75 76 77 78 79 80 81 82 83 84 |
# File 'lib/clogs/ui.rb', line 75 def solid_brush(color) b = malloc(L::FFI::DrawBrush) b.Type = BRUSH_SOLID r, g, bl, a = color b.R = r / 255.0 b.G = g / 255.0 b.B = bl / 255.0 b.A = (a || 255) / 255.0 b end |
.stroke_params(thickness, cap: CAP_FLAT, join: JOIN_MITER, dashes: nil) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/clogs/ui.rb', line 108 def stroke_params(thickness, cap: CAP_FLAT, join: JOIN_MITER, dashes: nil) sp = malloc(L::FFI::DrawStrokeParams) sp.Cap = cap sp.Join = join sp.Thickness = thickness.to_f sp.MiterLimit = 10.0 if dashes && !dashes.empty? buf = Fiddle::Pointer.malloc(dashes.size * 8, Fiddle::RUBY_FREE) buf[0, dashes.size * 8] = dashes.map(&:to_f).pack("d*") sp.Dashes = buf sp.NumDashes = dashes.size sp.instance_variable_set(:@clogs_dashes, buf) else sp.NumDashes = 0 end sp.DashPhase = 0.0 sp end |
.text_extents(layout) ⇒ Object
uiDrawTextLayoutExtents writes through two double pointers.
141 142 143 144 145 146 |
# File 'lib/clogs/ui.rb', line 141 def text_extents(layout) w = Fiddle::Pointer.malloc(8, Fiddle::RUBY_FREE) h = Fiddle::Pointer.malloc(8, Fiddle::RUBY_FREE) L.draw_text_layout_extents(layout, w, h) [w[0, 8].unpack1("d"), h[0, 8].unpack1("d")] end |