Class: Glimmer::SWT::WidgetProxy

Inherits:
Object
  • Object
show all
Includes:
Glimmer, PropertyOwner
Defined in:
lib/glimmer/swt/widget_proxy.rb

Constant Summary collapse

DEFAULT_INITIALIZERS =
{
  "composite" => lambda do |composite_proxy|
    if composite_proxy.layout.nil?
      layout = GridLayoutProxy.new(composite_proxy, [])
      composite_proxy.layout = layout
      layout.margin_width = 15
      layout.margin_height = 15
    end
  end,
#         "scrolled_composite" => lambda do |scrolled_composite|
#           scrolled_composite.expand_horizontal = true
#           scrolled_composite.expand_vertical = true
#         end,
#         "table" => lambda do |table|
#           table.setHeaderVisible(true)
#           table.setLinesVisible(true)
#         end,
  "table_column" => lambda do |table_column_proxy|
    table_column_proxy.width = 80
  end,
#         "group" => lambda do |group_proxy|
#           group_proxy.layout = GridLayoutProxy.new(group_proxy, []) if group.layout.nil?
#         end,
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PropertyOwner

#attribute_getter, #attribute_setter, #get_attribute

Constructor Details

#initialize(parent, args, block) ⇒ WidgetProxy

Returns a new instance of WidgetProxy.



100
101
102
103
104
105
106
107
108
# File 'lib/glimmer/swt/widget_proxy.rb', line 100

def initialize(parent, args, block)
  @parent = parent
  @args = args
  @block = block
  @children = Set.new # TODO consider moving to composite
  @enabled = true
  DEFAULT_INITIALIZERS[self.class.underscored_widget_name(self)]&.call(self)
  @parent.post_initialize_child(self) # TODO rename to post_initialize_child to be closer to glimmer-dsl-swt terminology
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def args
  @args
end

#backgroundObject

Returns the value of attribute background.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def background
  @background
end

#childrenObject (readonly)

Returns the value of attribute children.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def children
  @children
end

#enabledObject

Returns the value of attribute enabled.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def enabled
  @enabled
end

#focusObject

Returns the value of attribute focus.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def focus
  @focus
end

#fontObject

Returns the value of attribute font.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def font
  @font
end

#foregroundObject

Returns the value of attribute foreground.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def foreground
  @foreground
end

#parentObject (readonly)

Returns the value of attribute parent.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def parent
  @parent
end

#pathObject (readonly)

Returns the value of attribute path.



32
33
34
# File 'lib/glimmer/swt/widget_proxy.rb', line 32

def path
  @path
end

Class Method Details

.for(keyword, parent, args, block) ⇒ Object

Factory Method that translates a Glimmer DSL keyword into a WidgetProxy object



36
37
38
39
# File 'lib/glimmer/swt/widget_proxy.rb', line 36

def for(keyword, parent, args, block)
  the_widget_class = widget_class(keyword)
  the_widget_class.respond_to?(:create) ? the_widget_class.create(keyword, parent, args, block) : the_widget_class.new(parent, args, block)
end

.max_id_number_for(name) ⇒ Object



58
59
60
# File 'lib/glimmer/swt/widget_proxy.rb', line 58

def max_id_number_for(name)
  @max_id_numbers[name] = max_id_numbers[name] || 0
end

.max_id_numbersObject



62
63
64
# File 'lib/glimmer/swt/widget_proxy.rb', line 62

def max_id_numbers
  @max_id_numbers ||= reset_max_id_numbers!
end

.next_id_number_for(name) ⇒ Object



54
55
56
# File 'lib/glimmer/swt/widget_proxy.rb', line 54

def next_id_number_for(name)
  @max_id_numbers[name] = max_id_number_for(name) + 1
end

.reset_max_id_numbers!Object



66
67
68
# File 'lib/glimmer/swt/widget_proxy.rb', line 66

def reset_max_id_numbers!
  @max_id_numbers = {}
end

.underscored_widget_name(widget_proxy) ⇒ Object



70
71
72
# File 'lib/glimmer/swt/widget_proxy.rb', line 70

def underscored_widget_name(widget_proxy)
  widget_proxy.class.name.split(/::|\./).last.sub(/Proxy$/, '').underscore
end

.widget_class(keyword) ⇒ Object



41
42
43
44
45
46
47
48
# File 'lib/glimmer/swt/widget_proxy.rb', line 41

def widget_class(keyword)
  class_name_alternative = keyword.camelcase(:upper)
  class_name_main = "#{class_name_alternative}Proxy"
  Glimmer::SWT.const_get(class_name_main.to_sym) rescue Glimmer::SWT.const_get(class_name_alternative.to_sym)
rescue => e
  puts "Widget #{keyword} was not found!"
  nil
end

.widget_exists?(keyword) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/glimmer/swt/widget_proxy.rb', line 50

def widget_exists?(keyword)
  !!widget_class(keyword)
end

Instance Method Details

#add_css_class(css_class) ⇒ Object



229
230
231
# File 'lib/glimmer/swt/widget_proxy.rb', line 229

def add_css_class(css_class)
  dom_element.add_class(css_class)
end

#add_css_classes(css_classes_to_add) ⇒ Object



233
234
235
# File 'lib/glimmer/swt/widget_proxy.rb', line 233

def add_css_classes(css_classes_to_add)
  css_classes_to_add.each {|css_class| add_css_class(css_class)}
end

#add_observer(observer, property_name) ⇒ Object



324
325
326
327
328
329
330
# File 'lib/glimmer/swt/widget_proxy.rb', line 324

def add_observer(observer, property_name)
  property_listener_installers = self.class&.ancestors&.to_a.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
  widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
  widget_listener_installers.to_a.each do |widget_listener_installer|
    widget_listener_installer.call(observer)
  end
end

#apply_property_type_converters(attribute_name, args) ⇒ Object



337
338
339
340
341
342
343
344
345
346
347
# File 'lib/glimmer/swt/widget_proxy.rb', line 337

def apply_property_type_converters(attribute_name, args)
  if args.count == 1
    value = args.first
    converter = property_type_converters[attribute_name.to_sym]
    args[0] = converter.call(value) if converter
  end
#         if args.count == 1 && args.first.is_a?(ColorProxy)
#           g_color = args.first
#           args[0] = g_color.swt_color
#         end
end

#build_domObject



196
197
198
199
200
# File 'lib/glimmer/swt/widget_proxy.rb', line 196

def build_dom
  @dom = nil
  @dom = dom
  @dom = @parent.layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.layout
end

#can_handle_observation_request?(observation_request) ⇒ Boolean

Returns:

  • (Boolean)


286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/glimmer/swt/widget_proxy.rb', line 286

def can_handle_observation_request?(observation_request)
  # TODO sort this out for Opal
  observation_request = observation_request.to_s
  if observation_request.start_with?('on_swt_')
    constant_name = observation_request.sub(/^on_swt_/, '')
    SWTProxy.has_constant?(constant_name)
  elsif observation_request.start_with?('on_')
#           event = observation_request.sub(/^on_/, '')
#           can_add_listener?(event) || can_handle_drag_observation_request?(observation_request) || can_handle_drop_observation_request?(observation_request)
    true # TODO filter by valid listeners only in the future
  end
end

#clear_css_classesObject



245
246
247
# File 'lib/glimmer/swt/widget_proxy.rb', line 245

def clear_css_classes
  css_classes.each {|css_class| remove_css_class(css_class)}
end

#content(&block) ⇒ Object



202
203
204
# File 'lib/glimmer/swt/widget_proxy.rb', line 202

def content(&block)
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Opal::WidgetExpression.new, &block)
end

#css_classesObject



121
122
123
# File 'lib/glimmer/swt/widget_proxy.rb', line 121

def css_classes
  dom_element.attr('class').to_s.split
end

#disposeObject



125
126
127
# File 'lib/glimmer/swt/widget_proxy.rb', line 125

def dispose
  Document.find(path).remove
end

#dom_elementObject



253
254
255
256
# File 'lib/glimmer/swt/widget_proxy.rb', line 253

def dom_element
  # TODO consider making this pick an element in relation to its parent, allowing unhooked dom elements to be built if needed (unhooked to the visible page dom)
  Document.find(path)
end

#elementObject

Root element representing widget. Must be overridden by subclasses if different from div



134
135
136
# File 'lib/glimmer/swt/widget_proxy.rb', line 134

def element
  'div'
end

#handle_observation_request(keyword, &event_listener) ⇒ Object



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/glimmer/swt/widget_proxy.rb', line 299

def handle_observation_request(keyword, &event_listener)
  return unless observation_request_to_event_mapping.keys.include?(keyword)
  @observation_requests ||= {}
  @observation_requests[keyword] ||= Set.new
  event = nil
  delegate = nil
  [observation_request_to_event_mapping[keyword]].flatten.each do |mapping|
    @observation_requests[keyword] << event_listener
    event = mapping[:event]
    event_handler = mapping[:event_handler]
    event_element_css_selector = mapping[:event_element_css_selector]
    potential_event_listener = event_handler&.call(event_listener)
    event_listener = potential_event_listener || event_listener
    async_event_listener = lambda do |event|
      Async::Task.new do
        event_listener.call(event)
      end
    end
    the_listener_dom_element = event_element_css_selector ? Element[event_element_css_selector] : listener_dom_element
    delegate = the_listener_dom_element.on(event, &async_event_listener)
  end
  # TODO update code below for new WidgetProxy API
  EventListenerProxy.new(element_proxy: self, event: event, selector: selector, delegate: delegate)
end

#has_style?(symbol) ⇒ Boolean

Returns:

  • (Boolean)


249
250
251
# File 'lib/glimmer/swt/widget_proxy.rb', line 249

def has_style?(symbol)
  @args.include?(symbol) # not a very solid implementation. Bring SWT constants eventually
end

#idObject



215
216
217
# File 'lib/glimmer/swt/widget_proxy.rb', line 215

def id
  @id ||= "#{name}-#{WidgetProxy.next_id_number_for(name)}"
end

#id=(value) ⇒ Object

Sets id explicitly. Useful in cases of wanting to maintain a stable id



220
221
222
# File 'lib/glimmer/swt/widget_proxy.rb', line 220

def id=(value)
  @id = value
end

#listener_dom_elementObject



282
283
284
# File 'lib/glimmer/swt/widget_proxy.rb', line 282

def listener_dom_element
  Document.find(listener_path)
end

#listener_pathObject



278
279
280
# File 'lib/glimmer/swt/widget_proxy.rb', line 278

def listener_path
  path
end

#nameObject



211
212
213
# File 'lib/glimmer/swt/widget_proxy.rb', line 211

def name
  self.class.name.split('::').last.underscore.sub(/_proxy$/, '').gsub('_', '-')
end

#observation_request_to_event_mappingObject

Subclasses must override with their own mappings



207
208
209
# File 'lib/glimmer/swt/widget_proxy.rb', line 207

def observation_request_to_event_mapping
  {}
end

#parent_dom_elementObject



274
275
276
# File 'lib/glimmer/swt/widget_proxy.rb', line 274

def parent_dom_element
  Document.find(parent_path)
end

#parent_pathObject



171
172
173
# File 'lib/glimmer/swt/widget_proxy.rb', line 171

def parent_path
  @parent.path
end

#post_add_contentObject

Executes at the closing of a parent widget curly braces after all children/properties have been added/set



117
118
119
# File 'lib/glimmer/swt/widget_proxy.rb', line 117

def post_add_content
  # No Op by default
end

#post_initialize_child(child) ⇒ Object

Executes for the parent of a child that just got added



111
112
113
114
# File 'lib/glimmer/swt/widget_proxy.rb', line 111

def post_initialize_child(child)
  @children << child
  child.render
end

#property_type_convertersObject



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/glimmer/swt/widget_proxy.rb', line 349

def property_type_converters
  color_converter = lambda do |value|
    if value.is_a?(Symbol) || value.is_a?(String)
      ColorProxy.new(value)
    else
      value
    end
  end
  @property_type_converters ||= {
    :background => color_converter,
#           :background_image => lambda do |value|
#             if value.is_a?(String)
#               if value.start_with?('uri:classloader')
#                 value = value.sub(/^uri\:classloader\:\//, '')
#                 object = java.lang.Object.new
#                 value = object.java_class.resource_as_stream(value)
#                 value = java.io.BufferedInputStream.new(value)
#               end
#               image_data = ImageData.new(value)
#               on_event_Resize do |resize_event|
#                 new_image_data = image_data.scaledTo(@swt_widget.getSize.x, @swt_widget.getSize.y)
#                 @swt_widget.getBackgroundImage&.dispose
#                 @swt_widget.setBackgroundImage(Image.new(@swt_widget.getDisplay, new_image_data))
#               end
#               Image.new(@swt_widget.getDisplay, image_data)
#             else
#               value
#             end
#           end,
    :foreground => color_converter,
#           :font => lambda do |value|
#             if value.is_a?(Hash)
#               font_properties = value
#               FontProxy.new(self, font_properties).swt_font
#             else
#               value
#             end
#           end,
    :text => lambda do |value|
#             if swt_widget.is_a?(Browser)
#               value.to_s
#             else
        value.to_s
#             end
    end,
#           :visible => lambda do |value|
#             !!value
#           end,
  }
end

#remove_css_class(css_class) ⇒ Object



237
238
239
# File 'lib/glimmer/swt/widget_proxy.rb', line 237

def remove_css_class(css_class)
  dom_element.remove_class(css_class)
end

#remove_css_classes(css_classes_to_remove) ⇒ Object



241
242
243
# File 'lib/glimmer/swt/widget_proxy.rb', line 241

def remove_css_classes(css_classes_to_remove)
  css_classes_to_remove.each {|css_class| remove_css_class(css_class)}
end

#renderObject Also known as: redraw



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/glimmer/swt/widget_proxy.rb', line 175

def render
  old_element = dom_element
  brand_new = @dom.nil? || old_element.empty?
  build_dom
  if brand_new
    Document.find(parent_path).append(@dom)
  else
    old_element.replace_with(@dom)
  end
  @observation_requests&.clone&.each do |keyword, event_listener_set|
    event_listener_set.each do |event_listener|
      @observation_requests[keyword].delete(event_listener)
      handle_observation_request(keyword, &event_listener)
    end
  end
  children.each do |child|
    child.render
  end
end

#selectorObject

Subclasses can override with their own selector



225
226
227
# File 'lib/glimmer/swt/widget_proxy.rb', line 225

def selector
  "#{name}##{id}"
end

#set_attribute(attribute_name, *args) ⇒ Object



332
333
334
335
# File 'lib/glimmer/swt/widget_proxy.rb', line 332

def set_attribute(attribute_name, *args)
  apply_property_type_converters(attribute_name, args)
  super(attribute_name, *args) # PropertyOwner
end

#set_focusObject Also known as: setFocus



166
167
168
# File 'lib/glimmer/swt/widget_proxy.rb', line 166

def set_focus
  self.focus = true
end

#style_elementObject

TODO consider adding a default #dom method implementation for the common case, automatically relying on #element and other methods to build the dom html



260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/glimmer/swt/widget_proxy.rb', line 260

def style_element
  style_element_id = "#{id}-style"
  style_element_selector = "style##{style_element_id}"
  element = dom_element.find(style_element_selector)
  if element.empty?
    new_element = Element.new(:style)
    new_element.attr('id', style_element_id)
    new_element.attr('class', "#{name.gsub('_', '-')}-instance-style widget-instance-style")
    dom_element.prepend(new_element)
    element = dom_element.find(style_element_selector)
  end
  element
end

#widget_property_listener_installersObject



400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/glimmer/swt/widget_proxy.rb', line 400

def widget_property_listener_installers
  @swt_widget_property_listener_installers ||= {
#           WidgetProxy => {
#             :focus => lambda do |observer|
#               on_focus_gained { |focus_event|
#                 observer.call(true)
#               }
#               on_focus_lost { |focus_event|
#                 observer.call(false)
#               }
#             end,
#           },
    TextProxy => {
      :text => lambda do |observer|
        on_modify_text { |modify_event|
          observer.call(text)
        }
      end,
#             :caret_position => lambda do |observer|
#               on_event_keydown { |event|
#                 observer.call(getCaretPosition)
#               }
#               on_event_keyup { |event|
#                 observer.call(getCaretPosition)
#               }
#               on_event_mousedown { |event|
#                 observer.call(getCaretPosition)
#               }
#               on_event_mouseup { |event|
#                 observer.call(getCaretPosition)
#               }
#             end,
#             :selection => lambda do |observer|
#               on_event_keydown { |event|
#                 observer.call(getSelection)
#               }
#               on_event_keyup { |event|
#                 observer.call(getSelection)
#               }
#               on_event_mousedown { |event|
#                 observer.call(getSelection)
#               }
#               on_event_mouseup { |event|
#                 observer.call(getSelection)
#               }
#             end,
#             :selection_count => lambda do |observer|
#               on_event_keydown { |event|
#                 observer.call(getSelectionCount)
#               }
#               on_event_keyup { |event|
#                 observer.call(getSelectionCount)
#               }
#               on_event_mousedown { |event|
#                 observer.call(getSelectionCount)
#               }
#               on_event_mouseup { |event|
#                 observer.call(getSelectionCount)
#               }
#             end,
#             :top_index => lambda do |observer|
#               @last_top_index = getTopIndex
#               on_paint_control { |event|
#                 if getTopIndex != @last_top_index
#                   @last_top_index = getTopIndex
#                   observer.call(@last_top_index)
#                 end
#               }
#             end,
    },
#           Java::OrgEclipseSwtCustom::StyledText => {
#             :text => lambda do |observer|
#               on_modify_text { |modify_event|
#                 observer.call(getText)
#               }
#             end,
#           },
    DateTimeProxy => {
      :date_time => lambda do |observer|
        on_widget_selected { |selection_event|
          observer.call(date_time)
        }
      end
    },
    RadioProxy => { #radio?
      :selection => lambda do |observer|
        on_widget_selected { |selection_event|
          observer.call(selection)
        }
      end
    },
    TableProxy => {
      :selection => lambda do |observer|
        on_widget_selected { |selection_event|
          if has_style?(:multi)
            observer.call(selection.map(&:get_data))
          else
            observer.call(selection.first&.get_data)
          end
        }
      end,
    },
#           Java::OrgEclipseSwtWidgets::MenuItem => {
#             :selection => lambda do |observer|
#               on_widget_selected { |selection_event|
#                 observer.call(getSelection)
#               }
#             end
#           },
#           Java::OrgEclipseSwtWidgets::Spinner => {
#             :selection => lambda do |observer|
#               on_widget_selected { |selection_event|
#                 observer.call(getSelection)
#               }
#             end
#           },
  }
end