glimmer-dsl-wx 0.0.2 → 0.0.6

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.
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/wx/parent'
23
+
24
+ module Glimmer
25
+ module Wx
26
+ class ControlProxy
27
+ # Proxy for Wx frame objects
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class FrameProxy < ControlProxy
31
+ include Parent
32
+
33
+ attr_accessor :app_name
34
+
35
+ def initialize(keyword, parent, args, &block)
36
+ self.app_name = options.delete(:app_name)
37
+ super(keyword, parent, args, &block)
38
+ end
39
+
40
+ def title=(value)
41
+ # wxWidgets does not allow setting a frame title if set already
42
+ super if (options[:title] || options['title']).nil?
43
+ end
44
+
45
+ def post_add_content
46
+ super
47
+ show
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021-2023 Andy Maleh
1
+ # Copyright (c) 2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -19,53 +19,43 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require 'glimmer/libui/data_bindable'
22
+ require 'glimmer/wx/data_bindable'
23
+ require 'glimmer/wx/parent'
23
24
 
24
25
  module Glimmer
25
- module LibUI
26
- # Proxy for LibUI control objects
26
+ module Wx
27
+ # Proxy for Wx control objects
27
28
  #
28
29
  # Follows the Proxy Design Pattern
29
30
  class ControlProxy
30
31
  class << self
31
32
  def exists?(keyword)
32
- ::LibUI.respond_to?("new_#{keyword}") or
33
- ::LibUI.respond_to?(keyword) or
33
+ ::Wx.constants.include?(wx_constant_symbol(keyword)) or
34
34
  descendant_keyword_constant_map.keys.include?(keyword)
35
35
  end
36
36
 
37
37
  def create(keyword, parent, args, &block)
38
- widget_proxy_class(keyword).new(keyword, parent, args, &block).tap {|c| control_proxies << c}
38
+ control_proxy_class(keyword).new(keyword, parent, args, &block)
39
39
  end
40
40
 
41
- def widget_proxy_class(keyword)
41
+ def control_proxy_class(keyword)
42
42
  descendant_keyword_constant_map[keyword] || ControlProxy
43
43
  end
44
44
 
45
- # autosave all controls in this array to avoid garbage collection
46
- def control_proxies
47
- @@control_proxies = [] unless defined?(@@control_proxies)
48
- @@control_proxies
49
- end
50
-
51
- def main_window_proxy
52
- control_proxies.find {|c| c.is_a?(WindowProxy)}
53
- end
54
-
55
- def menu_proxies
56
- control_proxies.select {|c| c.keyword == 'menu' }
57
- end
58
-
59
- def image_proxies
60
- control_proxies.select {|c| c.keyword == 'image' }
45
+ def new_control(keyword, parent, args)
46
+ args = args.clone || []
47
+ if args.last.is_a?(Hash)
48
+ args[-1] = args[-1].clone
49
+ end
50
+ ::Wx.const_get(wx_constant_symbol(keyword)).new(parent, *args)
61
51
  end
62
52
 
63
- def new_control(keyword, args)
64
- ::LibUI.send("new_#{keyword}", *args)
53
+ def wx_constant_symbol(keyword)
54
+ keyword.to_s.camelcase(:upper).to_sym
65
55
  end
66
56
 
67
57
  def constant_symbol(keyword)
68
- "#{keyword.camelcase(:upper)}Proxy".to_sym
58
+ "#{keyword.to_s.camelcase(:upper)}Proxy".to_sym
69
59
  end
70
60
 
71
61
  def keyword(constant_symbol)
@@ -73,7 +63,7 @@ module Glimmer
73
63
  end
74
64
 
75
65
  def descendant_keyword_constant_map
76
- @descendant_keyword_constant_map ||= add_aliases_to_keyword_constant_map(map_descendant_keyword_constants_for(self))
66
+ @descendant_keyword_constant_map ||= map_descendant_keyword_constants_for(self)
77
67
  end
78
68
 
79
69
  def reset_descendant_keyword_constant_map
@@ -92,41 +82,12 @@ module Glimmer
92
82
  end
93
83
  accumulator
94
84
  end
95
-
96
- private
97
-
98
- def add_aliases_to_keyword_constant_map(keyword_constant_map)
99
- KEYWORD_ALIASES.each do |keyword, alias_keyword|
100
- keyword_constant_map[alias_keyword] = keyword_constant_map[keyword]
101
- end
102
- keyword_constant_map
103
- end
104
85
  end
105
86
 
106
87
  include DataBindable
107
88
 
108
- KEYWORD_ALIASES = {
109
- 'msg_box' => 'message_box',
110
- 'msg_box_error' => 'message_box_error',
111
- }
112
-
113
- BOOLEAN_PROPERTIES = %w[
114
- padded
115
- checked
116
- enabled toplevel visible
117
- read_only
118
- margined
119
- borderless fullscreen
120
- stretchy
121
- ]
122
-
123
- STRING_PROPERTIES = %w[
124
- text
125
- title
126
- ]
127
-
128
- # libui returns the contained LibUI object
129
- attr_reader :parent_proxy, :libui, :args, :keyword, :block, :content_added
89
+ # wx returns the contained LibUI object
90
+ attr_reader :parent_proxy, :wx, :args, :keyword, :block, :content_added
130
91
  alias content_added? content_added
131
92
 
132
93
  def initialize(keyword, parent, args, &block)
@@ -134,11 +95,14 @@ module Glimmer
134
95
  @parent_proxy = parent
135
96
  @args = args
136
97
  @block = block
137
- @enabled = true
138
98
  build_control
139
99
  post_add_content if @block.nil?
140
100
  end
141
101
 
102
+ def options
103
+ @args&.last&.is_a?(Hash) ? @args.last : {}
104
+ end
105
+
142
106
  # Subclasses may override to perform post add_content work (normally must call super)
143
107
  def post_add_content
144
108
  unless @content_added
@@ -152,40 +116,36 @@ module Glimmer
152
116
  # No Op by default
153
117
  end
154
118
 
155
- def window_proxy
119
+ # Returns closest frame ancestor or self if it is a frame
120
+ def frame_proxy
156
121
  found_proxy = self
157
- until found_proxy.nil? || found_proxy.is_a?(WindowProxy)
122
+ until found_proxy.nil? || found_proxy.is_a?(FrameProxy)
123
+ found_proxy = found_proxy.parent_proxy
124
+ end
125
+ found_proxy
126
+ end
127
+
128
+ # Returns closest control ancestor
129
+ def control_proxy
130
+ found_proxy = parent_proxy
131
+ until found_proxy.nil? || found_proxy.is_a?(ControlProxy)
158
132
  found_proxy = found_proxy.parent_proxy
159
133
  end
160
134
  found_proxy
161
135
  end
162
136
 
163
137
  def can_handle_listener?(listener_name)
164
- ::LibUI.respond_to?("#{libui_api_keyword}_#{listener_name}") ||
165
- ::LibUI.respond_to?("control_#{listener_name}") ||
166
- has_custom_listener?(listener_name)
138
+ listener_name.to_s.start_with?('on_')
139
+ # TODO figure out if there is a way to check this in Wx or not.
140
+ # has_custom_listener?(listener_name)
167
141
  end
168
142
 
169
143
  def handle_listener(listener_name, &listener)
170
- # replace first listener argument (control libui pointer) with actual Ruby libui object
171
- safe_listener = Proc.new { |*args| listener.call(self, *args[1..-1]) }
172
- if ::LibUI.respond_to?("#{libui_api_keyword}_#{listener_name}")
173
- if listeners[listener_name].nil?
174
- ::LibUI.send("#{libui_api_keyword}_#{listener_name}", libui) do |*args|
175
- listeners_for(listener_name).map { |listener| listener.call(*args) }.last
176
- end
177
- end
178
- listeners_for(listener_name) << safe_listener
179
- elsif ::LibUI.respond_to?("control_#{listener_name}")
180
- if listeners[listener_name].nil?
181
- ::LibUI.send("control_#{listener_name}", libui) do |*args|
182
- listeners_for(listener_name).map { |listener| listener.call(*args) }.last
183
- end
184
- end
185
- listeners_for(listener_name) << safe_listener
186
- elsif has_custom_listener?(listener_name)
187
- handle_custom_listener(listener_name, &listener)
188
- end
144
+ event = listener_name.to_s.sub('on_', '')
145
+ frame_proxy.wx.send("evt_#{event}", @wx, &listener)
146
+ # elsif has_custom_listener?(listener_name)
147
+ # handle_custom_listener(listener_name, &listener)
148
+ # end
189
149
  end
190
150
 
191
151
  def listeners
@@ -238,31 +198,14 @@ module Glimmer
238
198
  end
239
199
 
240
200
  def respond_to?(method_name, *args, &block)
241
- respond_to_libui?(method_name, *args, &block) ||
242
- (
243
- append_properties.include?(method_name.to_s) ||
244
- (append_properties.include?(method_name.to_s.sub(/\?$/, '')) && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, ''))) ||
245
- append_properties.include?(method_name.to_s.sub(/=$/, ''))
246
- ) ||
201
+ @wx.respond_to?(method_name, true) ||
247
202
  can_handle_listener?(method_name.to_s) ||
248
203
  super(method_name, true)
249
204
  end
250
205
 
251
- def respond_to_libui?(method_name, *args, &block)
252
- ::LibUI.respond_to?("control_#{method_name}") or
253
- (::LibUI.respond_to?("control_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) or
254
- ::LibUI.respond_to?("control_set_#{method_name.to_s.sub(/=$/, '')}") or
255
- ::LibUI.respond_to?("#{libui_api_keyword}_#{method_name}") or
256
- (::LibUI.respond_to?("#{libui_api_keyword}_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) or
257
- ::LibUI.respond_to?("#{libui_api_keyword}_set_#{method_name.to_s.sub(/=$/, '')}")
258
- end
259
-
260
206
  def method_missing(method_name, *args, &block)
261
- if respond_to_libui?(method_name, *args, &block)
262
- send_to_libui(method_name, *args, &block)
263
- elsif append_properties.include?(method_name.to_s) ||
264
- append_properties.include?(method_name.to_s.sub(/(=|\?)$/, ''))
265
- append_property(method_name, *args)
207
+ if @wx.respond_to?(method_name, true)
208
+ @wx.send(method_name, *args, &block)
266
209
  elsif can_handle_listener?(method_name.to_s)
267
210
  handle_listener(method_name.to_s, &block)
268
211
  else
@@ -270,116 +213,6 @@ module Glimmer
270
213
  end
271
214
  end
272
215
 
273
- def send_to_libui(method_name, *args, &block)
274
- if ::LibUI.respond_to?("#{libui_api_keyword}_#{method_name.to_s.sub(/\?$/, '')}") && args.empty?
275
- property = method_name.to_s.sub(/\?$/, '')
276
- value = ::LibUI.send("#{libui_api_keyword}_#{property}", libui, *args)
277
- handle_string_property(property, handle_boolean_property(property, value))
278
- elsif ::LibUI.respond_to?("#{libui_api_keyword}_get_#{method_name.to_s.sub(/\?$/, '')}") && args.empty?
279
- property = method_name.to_s.sub(/\?$/, '')
280
- value = ::LibUI.send("#{libui_api_keyword}_get_#{property}", libui, *args)
281
- handle_string_property(property, handle_boolean_property(property, value))
282
- elsif ::LibUI.respond_to?("#{libui_api_keyword}_set_#{method_name.to_s.sub(/=$/, '')}") && !args.empty?
283
- property = method_name.to_s.sub(/=$/, '')
284
- args[0] = Glimmer::LibUI.boolean_to_integer(args.first) if BOOLEAN_PROPERTIES.include?(property) && (args.first.is_a?(TrueClass) || args.first.is_a?(FalseClass))
285
- args[0] = '' if STRING_PROPERTIES.include?(property) && args.first == nil
286
- if property.to_s == 'checked'
287
- current_value = Glimmer::LibUI.integer_to_boolean(::LibUI.send("#{libui_api_keyword}_checked", libui), allow_nil: false)
288
- new_value = Glimmer::LibUI.integer_to_boolean(args[0], allow_nil: false)
289
- ::LibUI.send("#{libui_api_keyword}_set_#{property}", libui, *args) if new_value != current_value
290
- else
291
- ::LibUI.send("#{libui_api_keyword}_set_#{property}", libui, *args)
292
- end
293
- elsif ::LibUI.respond_to?("#{libui_api_keyword}_#{method_name}") && !args.empty?
294
- ::LibUI.send("#{libui_api_keyword}_#{method_name}", libui, *args)
295
- elsif ::LibUI.respond_to?("control_#{method_name.to_s.sub(/\?$/, '')}") && args.empty?
296
- property = method_name.to_s.sub(/\?$/, '')
297
- value = ::LibUI.send("control_#{property}", libui, *args)
298
- handle_string_property(property, handle_boolean_property(property, value))
299
- elsif ::LibUI.respond_to?("control_set_#{method_name.to_s.sub(/=$/, '')}")
300
- property = method_name.to_s.sub(/=$/, '')
301
- args[0] = Glimmer::LibUI.boolean_to_integer(args.first) if BOOLEAN_PROPERTIES.include?(property) && (args.first.is_a?(TrueClass) || args.first.is_a?(FalseClass))
302
- args[0] = '' if STRING_PROPERTIES.include?(property) && args.first == nil
303
- ::LibUI.send("control_set_#{method_name.to_s.sub(/=$/, '')}", libui, *args)
304
- elsif ::LibUI.respond_to?("control_#{method_name}") && !args.empty?
305
- ::LibUI.send("control_#{method_name}", libui, *args)
306
- end
307
- end
308
-
309
- def append_properties
310
- @parent_proxy&.class&.constants&.include?(:APPEND_PROPERTIES) ? @parent_proxy.class::APPEND_PROPERTIES : []
311
- end
312
-
313
- def append_property(property, value = nil)
314
- property = property.to_s.sub(/(=|\?)$/, '')
315
- @append_property_hash ||= {}
316
- if value.nil?
317
- value = @append_property_hash[property]
318
- handle_string_property(property, handle_boolean_property(property, value))
319
- else
320
- value = Glimmer::LibUI.boolean_to_integer(value) if BOOLEAN_PROPERTIES.include?(property) && (value.is_a?(TrueClass) || value.is_a?(FalseClass))
321
- @append_property_hash[property] = value
322
- end
323
- end
324
-
325
- def libui_api_keyword
326
- @keyword
327
- end
328
-
329
- def destroy
330
- # TODO exclude menus from this initial return
331
- return if !is_a?(ControlProxy::WindowProxy) && ControlProxy.main_window_proxy&.destroying?
332
- data_binding_model_attribute_observer_registrations.each(&:deregister)
333
- if parent_proxy.nil?
334
- default_destroy
335
- else
336
- parent_proxy.destroy_child(self)
337
- end
338
- end
339
-
340
- def destroy_child(child)
341
- child.default_destroy
342
- children.delete(child)
343
- end
344
-
345
- def default_destroy
346
- deregister_all_custom_listeners
347
- send_to_libui('destroy')
348
- ControlProxy.control_proxies.delete(self)
349
- end
350
-
351
- def enabled(value = nil)
352
- if value.nil?
353
- @enabled
354
- elsif value != @enabled
355
- @enabled = value == 1 || value
356
- if value == 1 || value
357
- send_to_libui('enable')
358
- else
359
- send_to_libui('disable')
360
- end
361
- end
362
- end
363
- alias enabled? enabled
364
- alias set_enabled enabled
365
- alias enabled= enabled
366
-
367
- def visible(value = nil)
368
- current_value = send_to_libui('visible')
369
- if value.nil?
370
- current_value
371
- elsif value != current_value
372
- if value == 1 || value
373
- send_to_libui('show')
374
- else
375
- send_to_libui('hide')
376
- end
377
- end
378
- end
379
- alias visible? visible
380
- alias set_visible visible
381
- alias visible= visible
382
-
383
216
  def content(&block)
384
217
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Libui::ControlExpression.new, @keyword, {post_add_content: @content_added}, &block)
385
218
  end
@@ -387,20 +220,8 @@ module Glimmer
387
220
  private
388
221
 
389
222
  def build_control
390
- @libui = if ::LibUI.respond_to?("new_#{keyword}")
391
- ControlProxy.new_control(@keyword, @args)
392
- elsif ::LibUI.respond_to?(keyword)
393
- @args[0] = @args.first.libui if @args.first.is_a?(ControlProxy)
394
- ::LibUI.send(@keyword, *@args)
395
- end
396
- end
397
-
398
- def handle_boolean_property(property, value)
399
- BOOLEAN_PROPERTIES.include?(property) ? Glimmer::LibUI.integer_to_boolean(value) : value
400
- end
401
-
402
- def handle_string_property(property, value)
403
- STRING_PROPERTIES.include?(property) ? value.to_s : value
223
+ # must pass control_proxy.wx as parent because the direct parent might be a sizer
224
+ @wx = ControlProxy.new_control(@keyword, control_proxy&.wx, @args)
404
225
  end
405
226
  end
406
227
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021-2023 Andy Maleh
1
+ # Copyright (c) 2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -20,7 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  module Glimmer
23
- module LibUI
23
+ module Wx
24
24
  # Parent controls and shapes who have children and add child post_initialize_child
25
25
  module DataBindable
26
26
  # Sets up read/write (bidirectional) data-binding
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021-2023 Andy Maleh
1
+ # Copyright (c) 2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -20,7 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  module Glimmer
23
- module LibUI
23
+ module Wx
24
24
  # Parent controls and shapes who have children and add child post_initialize_child
25
25
  module Parent
26
26
  # Subclasses can override and must call super (passing add_child: false to cancel adding child to children)
@@ -0,0 +1,150 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/wx/data_bindable'
23
+ require 'glimmer/wx/parent'
24
+
25
+ module Glimmer
26
+ module Wx
27
+ # Proxy for Wx sizer objects
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class SizerProxy
31
+ class << self
32
+ def exists?(keyword)
33
+ keyword.end_with?('_sizer') and
34
+ (
35
+ ::Wx.constants.include?(wx_constant_symbol(keyword)) or
36
+ descendant_keyword_constant_map.keys.include?(keyword)
37
+ )
38
+ end
39
+
40
+ def create(keyword, parent, args, &block)
41
+ sizer_proxy_class(keyword).new(keyword, parent, args, &block)
42
+ end
43
+
44
+ def sizer_proxy_class(keyword)
45
+ descendant_keyword_constant_map[keyword] || SizerProxy
46
+ end
47
+
48
+ def new_sizer(keyword, parent, args)
49
+ args = args.clone || []
50
+ if args.last.is_a?(Hash)
51
+ args[-1] = args[-1].clone
52
+ end
53
+ ::Wx.const_get(wx_constant_symbol(keyword)).new(*args)
54
+ end
55
+
56
+ def wx_constant_symbol(keyword)
57
+ keyword.to_s.camelcase(:upper).to_sym
58
+ end
59
+
60
+ def constant_symbol(keyword)
61
+ "#{keyword.to_s.camelcase(:upper)}Proxy".to_sym
62
+ end
63
+
64
+ def keyword(constant_symbol)
65
+ constant_symbol.to_s.underscore.sub(/_proxy$/, '')
66
+ end
67
+
68
+ def descendant_keyword_constant_map
69
+ @descendant_keyword_constant_map ||= map_descendant_keyword_constants_for(self)
70
+ end
71
+
72
+ def reset_descendant_keyword_constant_map
73
+ @descendant_keyword_constant_map = nil
74
+ descendant_keyword_constant_map
75
+ end
76
+
77
+ def map_descendant_keyword_constants_for(klass, accumulator: {})
78
+ klass.constants.map do |constant_symbol|
79
+ [constant_symbol, klass.const_get(constant_symbol)]
80
+ end.select do |constant_symbol, constant|
81
+ constant.is_a?(Module) && !accumulator.values.include?(constant)
82
+ end.each do |constant_symbol, constant|
83
+ accumulator[keyword(constant_symbol)] = constant
84
+ map_descendant_keyword_constants_for(constant, accumulator: accumulator)
85
+ end
86
+ accumulator
87
+ end
88
+ end
89
+
90
+ include DataBindable
91
+
92
+ # wx returns the contained LibUI object
93
+ attr_reader :parent_proxy, :wx, :args, :keyword, :block, :content_added
94
+ alias content_added? content_added
95
+
96
+ def initialize(keyword, parent, args, &block)
97
+ @keyword = keyword
98
+ @parent_proxy = parent
99
+ @args = args
100
+ @block = block
101
+ build_sizer
102
+ post_add_content if @block.nil?
103
+ end
104
+
105
+ # Subclasses may override to perform post add_content work (normally must call super)
106
+ def post_add_content
107
+ unless @content_added
108
+ @parent_proxy&.post_initialize_child(self)
109
+ @content_added = true
110
+ end
111
+ end
112
+
113
+ # Subclasses may override to perform post initialization work on an added child
114
+ def post_initialize_child(child)
115
+ # No Op by default
116
+ end
117
+
118
+ def respond_to?(method_name, *args, &block)
119
+ @wx.respond_to?(method_name, true) ||
120
+ super(method_name, true)
121
+ end
122
+
123
+ def method_missing(method_name, *args, &block)
124
+ if @wx.respond_to?(method_name, true)
125
+ @wx.send(method_name, *args, &block)
126
+ else
127
+ super
128
+ end
129
+ end
130
+
131
+ def content(&block)
132
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Libui::SizerExpression.new, @keyword, {post_add_content: @content_added}, &block)
133
+ end
134
+
135
+ def add(control_proxy, *args, &block)
136
+ @wx.add(control_proxy.wx, *args)
137
+ end
138
+
139
+ private
140
+
141
+ def build_sizer
142
+ @wx = SizerProxy.new_sizer(@keyword, @parent_proxy.wx, @args)
143
+ parent_proxy.sizer = @wx if parent_proxy.is_a?(Glimmer::Wx::ControlProxy)
144
+ @wx
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ Dir[File.expand_path("./#{File.basename(__FILE__, '.rb')}/*.rb", __dir__)].each {|f| require f}
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021-2023 Andy Maleh
1
+ # Copyright (c) 2023 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-wx'
23
+
24
+ include Glimmer
25
+
26
+ frame(title: 'Hello, Button!') { |main_frame|
27
+ h_box_sizer {
28
+ button(label: 'Click To Find Who Built This!') {
29
+ sizer_args 0, Wx::RIGHT, 10
30
+
31
+ on_button do
32
+ about_box(
33
+ name: main_frame.title,
34
+ version: Wx::WXRUBY_VERSION,
35
+ description: "This is the Hello, Button! sample",
36
+ developers: ['The Glimmer DSL for WX Development Team']
37
+ )
38
+ end
39
+ }
40
+ }
41
+ }