class Glimmer::Tk::WidgetProxy

Proxy for Tk Widget objects

Follows the Proxy Design Pattern

Constants

DEFAULT_INITIALIZERS

Attributes

args[R]
parent_proxy[R]
tk[R]

Public Class Methods

create(keyword, parent, args) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 43
def create(keyword, parent, args)
  widget_proxy_class(keyword).new(keyword, parent, args)
end
new(underscored_widget_name, parent_proxy, args) click to toggle source

Initializes a new Tk Widget

Styles is a comma separate list of symbols representing Tk styles in lower case

# File lib/glimmer/tk/widget_proxy.rb, line 81
def initialize(underscored_widget_name, parent_proxy, args)
  @parent_proxy = parent_proxy
  @args = args
  tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
  @tk = tk_widget_class.new(@parent_proxy.tk, *args)
  # a common widget initializer
  @tk.grid
  DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
  @parent_proxy.post_initialize_child(self)
end
tk_widget_class_for(underscored_widget_name) click to toggle source

This supports widgets in and out of basic Tk

# File lib/glimmer/tk/widget_proxy.rb, line 57
def tk_widget_class_for(underscored_widget_name)
  tk_widget_class_basename = underscored_widget_name.camelcase(:upper)
  potential_tk_widget_class_names = [
    "::Tk::Tile::#{tk_widget_class_basename}",
    "::Tk::#{tk_widget_class_basename}",
    "::Tk#{tk_widget_class_basename}",
    "::Glimmer::Tk::#{tk_widget_class_basename}Proxy",
  ]
  tk_widget_class = nil
  potential_tk_widget_class_names.each do |tk_widget_name|
    begin
      tk_widget_class = eval(tk_widget_name)
      break
    rescue RuntimeError, SyntaxError, NameError => e
      Glimmer::Config.logger.debug e.full_message
    end
  end
  tk_widget_class
end
widget_exists?(underscored_widget_name) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 102
def self.widget_exists?(underscored_widget_name)
  !!tk_widget_class_for(underscored_widget_name)
end
widget_proxy_class(keyword) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 47
def widget_proxy_class(keyword)
  begin
    class_name = "#{keyword.camelcase(:upper)}Proxy".to_sym
    Glimmer::Tk.const_get(class_name)
  rescue
    Glimmer::Tk::WidgetProxy
  end
end

Public Instance Methods

add_observer(observer, attribute) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 220
def add_observer(observer, attribute)
  attribute_listener_installers = @tk.class.ancestors.map {|ancestor| widget_attribute_listener_installers[ancestor]}.compact
  widget_listener_installers = attribute_listener_installers.map{|installer| installer[attribute.to_s]}.compact if !attribute_listener_installers.empty?
  widget_listener_installers.to_a.first&.call(observer)
end
attribute_setter(attribute) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 161
def attribute_setter(attribute)
  "#{attribute}="
end
content(&block) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 226
def content(&block)
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, &block)
end
get_attribute(attribute) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 150
def get_attribute(attribute)
  widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
  if widget_custom_attribute
    widget_custom_attribute[:getter][:invoker].call(@tk, args)
  elsif tk_widget_has_attribute_getter_setter?(attribute)
    @tk.send(attribute)
  else
    send(attribute)
  end
end
has_attribute?(attribute, *args) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 130
def has_attribute?(attribute, *args)
  (widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]) ||
    tk_widget_has_attribute_setter?(attribute) ||
    tk_widget_has_attribute_getter_setter?(attribute) ||
    respond_to?(attribute_setter(attribute), args)
end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
# File lib/glimmer/tk/widget_proxy.rb, line 230
def method_missing(method, *args, &block)
  method = method.to_s
  if args.empty? && block.nil? && widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method]
    get_attribute(method)
  elsif widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method.sub(/=$/, '')] && method.end_with?('=') && block.nil?
    set_attribute(method.sub(/=$/, ''), *args)
  else
    tk.send(method, *args, &block)
  end
rescue => e
  Glimmer::Config.logger.debug {"Neither WidgetProxy nor #{tk.class.name} can handle the method ##{method}"}
  super(method.to_sym, *args, &block)
end
post_add_content() click to toggle source

Subclasses may override to perform post add_content work

# File lib/glimmer/tk/widget_proxy.rb, line 98
def post_add_content
  # No Op by default
end
post_initialize_child(child) click to toggle source

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

# File lib/glimmer/tk/widget_proxy.rb, line 93
def post_initialize_child(child)
  # No Op by default
end
respond_to?(method, *args, &block) click to toggle source
Calls superclass method
# File lib/glimmer/tk/widget_proxy.rb, line 244
def respond_to?(method, *args, &block)
  super ||
    tk.respond_to?(method, *args, &block)
end
set_attribute(attribute, *args) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 137
def set_attribute(attribute, *args)
  widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
  if widget_custom_attribute
    widget_custom_attribute[:setter][:invoker].call(@tk, args)
  elsif tk_widget_has_attribute_setter?(attribute)
    @tk.send(attribute_setter(attribute), *args) unless @tk.send(attribute) == args.first
  elsif tk_widget_has_attribute_getter_setter?(attribute)
    @tk.send(attribute, *args) unless @tk.send(attribute) == args.first
  else
    send(attribute_setter(attribute), args)
  end
end
tk_widget_has_attribute_getter_setter?(attribute) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 118
def tk_widget_has_attribute_getter_setter?(attribute)
  result = nil
  begin
    # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
    @tk.send(attribute, @tk.send(attribute))
    result = true
  rescue => e
    result = false
  end
  result
end
tk_widget_has_attribute_setter?(attribute) click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 106
def tk_widget_has_attribute_setter?(attribute)
  result = nil
  begin
    # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
    @tk.send(attribute_setter(attribute), @tk.send(attribute))
    result = true
  rescue => e
    result = false
  end
  result
end
widget_attribute_listener_installers() click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 188
def widget_attribute_listener_installers
  @tk_widget_attribute_listener_installers ||= {
    ::Tk::Tile::TCombobox => {
      'text' => lambda do |observer|
        if observer.is_a?(Glimmer::DataBinding::ModelBinding)
          model = observer.model
          options_model_property = observer.property_name + '_options'
          @tk.values = model.send(options_model_property) if model.respond_to?(options_model_property)
        end
        @tk.bind('<ComboboxSelected>') {
          observer.call(@tk.textvariable.value)
        }
      end,
    },
    ::Tk::Tile::TEntry => {
      'text' => lambda do |observer|
        tk.validate = 'key'
        tk.validatecommand { |new_tk_variable|
          @text_variable_edit = new_tk_variable.value != @tk.textvariable.value
          if @text_variable_edit
            observer.call(new_tk_variable.value)
            @text_variable_edit = nil
            true
          else
            false
          end
        }
      end,
    },
  }
end
widget_custom_attribute_mapping() click to toggle source
# File lib/glimmer/tk/widget_proxy.rb, line 165
def widget_custom_attribute_mapping
  @widget_custom_attribute_mapping ||= {
    ::Tk::Tile::TCombobox => {
      'text' => {
        getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
        setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
      },
    },
    ::Tk::Tile::TLabel => {
      'text' => {
        getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
        setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
      },
    },
    ::Tk::Tile::TEntry => {
      'text' => {
        getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
        setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first unless @text_variable_edit }},
      },
    },
  }
end