glimmer-dsl-wx 0.0.2 → 0.0.6

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