Module: Glimmer::LibUI::CustomControl

Includes:
DataBinding::ObservableModel, SuperModule
Included in:
CodeArea, CodeEntry, RefinedTable, CustomWindow
Defined in:
lib/glimmer/libui/custom_control.rb,
lib/glimmer/libui/custom_control/code_area.rb,
lib/glimmer/libui/custom_control/code_entry.rb,
lib/glimmer/libui/custom_control/refined_table.rb

Defined Under Namespace

Modules: GlimmerSupersedable Classes: CodeArea, CodeEntry, RefinedTable

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def args
  @args
end

#body_rootObject (readonly)

Returns the value of attribute body_root.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def body_root
  @body_root
end

#content(*args, &block) ⇒ Object (readonly)

Returns content block if used as an attribute reader (no args) Otherwise, if a block is passed, it adds it as content to this custom control



246
247
248
# File 'lib/glimmer/libui/custom_control.rb', line 246

def content
  @content
end

#keywordObject (readonly)

Returns the value of attribute keyword.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def keyword
  @keyword
end

#libuiObject (readonly)

Returns the value of attribute libui.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def libui
  @libui
end

#optionsObject (readonly)

Returns the value of attribute options.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def options
  @options
end

#parentObject (readonly)

Returns the value of attribute parent.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def parent
  @parent
end

#parent_proxyObject (readonly)

Returns the value of attribute parent_proxy.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def parent_proxy
  @parent_proxy
end

#slot_controlsObject (readonly)

Returns the value of attribute slot_controls.



192
193
194
# File 'lib/glimmer/libui/custom_control.rb', line 192

def slot_controls
  @slot_controls
end

Class Method Details

.add_custom_control_namespaces_for(klass) ⇒ Object



115
116
117
118
119
# File 'lib/glimmer/libui/custom_control.rb', line 115

def add_custom_control_namespaces_for(klass)
  Glimmer::LibUI::CustomControl.namespaces_for_class(klass).drop(1).each do |namespace|
    Glimmer::LibUI::CustomControl.custom_control_namespaces << namespace
  end
end

.after_body(&block) ⇒ Object



183
184
185
# File 'lib/glimmer/libui/custom_control.rb', line 183

def after_body(&block)
  @after_body_block = block
end

.before_body(&block) ⇒ Object



175
176
177
# File 'lib/glimmer/libui/custom_control.rb', line 175

def before_body(&block)
  @before_body_block = block
end

.body(&block) ⇒ Object



179
180
181
# File 'lib/glimmer/libui/custom_control.rb', line 179

def body(&block)
  @body_block = block
end

.custom_control_namespacesObject



129
130
131
# File 'lib/glimmer/libui/custom_control.rb', line 129

def custom_control_namespaces
  @custom_control_namespaces ||= reset_custom_control_namespaces
end

.custom_controls_being_interpretedObject



187
188
189
# File 'lib/glimmer/libui/custom_control.rb', line 187

def custom_controls_being_interpreted
  @custom_controls_being_interpreted ||= []
end

.def_option_attr_accessors(new_options) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/glimmer/libui/custom_control.rb', line 161

def def_option_attr_accessors(new_options)
  new_options.each do |option, default|
    class_eval <<-end_eval, __FILE__, __LINE__
      def #{option}
        options[:#{option}]
      end
      
      def #{option}=(option_value)
        self.options[:#{option}] = option_value
      end
    end_eval
  end
end

.flyweight_custom_control_classesObject

Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.



101
102
103
# File 'lib/glimmer/libui/custom_control.rb', line 101

def flyweight_custom_control_classes
  @flyweight_custom_control_classes ||= {}
end

.for(keyword) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/glimmer/libui/custom_control.rb', line 67

def for(keyword)
  unless flyweight_custom_control_classes.keys.include?(keyword)
    begin
      extracted_namespaces = keyword.
        to_s.
        split(/__/).map do |namespace|
          namespace.camelcase(:upper)
        end
      custom_control_namespaces.each do |base|
        extracted_namespaces.reduce(base) do |result, namespace|
          if !result.constants.include?(namespace)
            namespace = result.constants.detect {|c| c.to_s.upcase == namespace.to_s.upcase } || namespace
          end
          begin
            flyweight_custom_control_classes[keyword] = constant = result.const_get(namespace)
            return constant if constant.ancestors.include?(Glimmer::LibUI::CustomControl)
            flyweight_custom_control_classes[keyword] = constant
          rescue => e
            # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
            flyweight_custom_control_classes[keyword] = result
          end
        end
      end
      raise "#{keyword} has no custom control class!"
    rescue => e
      Glimmer::Config.logger.debug {e.message}
      Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
      flyweight_custom_control_classes[keyword] = nil
    end
  end
  flyweight_custom_control_classes[keyword]
end

.keywordObject

Returns keyword to use for this custom control



106
107
108
# File 'lib/glimmer/libui/custom_control.rb', line 106

def keyword
  self.name.underscore.gsub('::', '__')
end

.namespaces_for_class(m) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/glimmer/libui/custom_control.rb', line 121

def namespaces_for_class(m)
  return [m] if m.name.nil?
  namespace_constants = m.name.split(/::/).map(&:to_sym)
  namespace_constants.reduce([Object]) do |output, namespace_constant|
    output += [output.last.const_get(namespace_constant)]
  end[1..-1].uniq.reverse
end

.option(new_option, default: nil) ⇒ Object



154
155
156
157
158
159
# File 'lib/glimmer/libui/custom_control.rb', line 154

def option(new_option, default: nil)
  new_option = new_option.to_s.to_sym
  new_options = {new_option => default}
  @options = options.merge(new_options)
  def_option_attr_accessors(new_options)
end

.options(*new_options) ⇒ Object

Allows defining convenience option accessors for an array of option names Example: ‘options :color1, :color2` defines `#color1` and `#color2` where they return the instance values `options` and `options` respectively. Can be called multiple times to set more options additively. When passed no arguments, it returns list of all option names captured so far



143
144
145
146
147
148
149
150
151
152
# File 'lib/glimmer/libui/custom_control.rb', line 143

def options(*new_options)
  new_options = new_options.compact.map(&:to_s).map(&:to_sym)
  if new_options.empty?
    @options ||= {} # maps options to defaults
  else
    new_options = new_options.reduce({}) {|new_options_hash, new_option| new_options_hash.merge(new_option => nil)}
    @options = options.merge(new_options)
    def_option_attr_accessors(new_options)
  end
end

.reset_custom_control_namespacesObject



133
134
135
# File 'lib/glimmer/libui/custom_control.rb', line 133

def reset_custom_control_namespaces
  @custom_control_namespaces = Set[Object, Glimmer::LibUI]
end

.shortcut_keywordObject

Returns shortcut keyword to use for this custom control (keyword minus namespace)



111
112
113
# File 'lib/glimmer/libui/custom_control.rb', line 111

def shortcut_keyword
  self.name.underscore.gsub('::', '__').split('__').last
end

Instance Method Details

#can_handle_listener?(listener) ⇒ Boolean

Returns:

  • (Boolean)


227
228
229
# File 'lib/glimmer/libui/custom_control.rb', line 227

def can_handle_listener?(listener)
  body_root&.can_handle_listener?(listener.to_s)
end

#handle_listener(listener, &block) ⇒ Object



231
232
233
# File 'lib/glimmer/libui/custom_control.rb', line 231

def handle_listener(listener, &block)
  body_root.handle_listener(listener.to_s, &block)
end

#has_instance_method?(method_name) ⇒ Boolean

This method ensures it has an instance method not coming from Glimmer DSL

Returns:

  • (Boolean)


236
237
238
239
240
241
242
# File 'lib/glimmer/libui/custom_control.rb', line 236

def has_instance_method?(method_name)
  respond_to?(method_name) and
    !@body_root.respond_to_libui?(method_name) and
    (method(method_name) rescue nil) and
    !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
    !method(method_name)&.source_location&.first&.include?('glimmer/libui/control_proxy.rb')
end

#initialize(keyword, parent, args, options, &content) ⇒ Object

Raises:

  • (Glimmer::Error)


194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/glimmer/libui/custom_control.rb', line 194

def initialize(keyword, parent, args, options, &content)
  CustomControl.custom_controls_being_interpreted << self
  @parent_proxy = @parent = parent
  options ||= {}
  @options = self.class.options.merge(options)
  @slot_controls = {}
  @content = ProcTracker.new(content) if content
  execute_hook('before_body')
  body_block = self.class.instance_variable_get("@body_block")
  raise Glimmer::Error, 'Invalid custom control for having no body! Please define body block!' if body_block.nil?
  @body_root = instance_exec(&body_block)
  raise Glimmer::Error, 'Invalid custom control for having an empty body! Please fill body block!' if @body_root.nil?
  @libui = @body_root.libui
  execute_hook('after_body')
  # TODO deregister all observer_registrations on destroy of the control once that listener is supported
  # (on_destroy) unless it is the last window closing, in which case exit faster
  post_add_content if content.nil?
end

#observer_registrationsObject



223
224
225
# File 'lib/glimmer/libui/custom_control.rb', line 223

def observer_registrations
  @observer_registrations ||= []
end

#post_add_contentObject



218
219
220
221
# File 'lib/glimmer/libui/custom_control.rb', line 218

def post_add_content
  @parent_proxy&.post_initialize_child(@body_root)
  Glimmer::LibUI::CustomControl.custom_controls_being_interpreted.pop
end

#post_initialize_child(child) ⇒ Object

Subclasses may override to perform post initialization work on an added child



214
215
216
# File 'lib/glimmer/libui/custom_control.rb', line 214

def post_initialize_child(child)
  # No Op by default
end