require 'fox16/responder' module Fox # # FXPseudoTarget instances act as the message target for any widgets that # elect to use the #connect method to map certain message types to # blocks. # class FXPseudoTarget < FXObject include Responder @@targets_of_pending_timers = {} @@targets_of_pending_chores = {} @@targets_of_pending_signals = {} @@targets_of_pending_inputs = {} # # Returns an initialized FXPseudoTarget object. # def initialize super @context = {} end # # Store an association between a message of type # _message_type_ with a callable object. # def pconnect(message_type, callable_object, params={}) @context[message_type] = { :callable => callable_object, :params => params } FXMAPTYPE(message_type, :onHandleMsg) case message_type when SEL_TIMEOUT @@targets_of_pending_timers[self] = self when SEL_CHORE @@targets_of_pending_chores[self] = self when SEL_SIGNAL @@targets_of_pending_signals[self] = self when SEL_IO_READ, SEL_IO_WRITE, SEL_IO_EXCEPT @@targets_of_pending_inputs[self] = self end end # # Handle a message from _sender_, with selector _sel_ and # message data _ptr_. # def onHandleMsg(sender, sel, ptr) message_type = Fox.FXSELTYPE(sel) ctx = @context[message_type] callable_object = ctx[:callable] params = ctx[:params] result = callable_object.call(sender, sel, ptr) case message_type when SEL_TIMEOUT if params[:repeat] FXApp.instance.addTimeout(params[:delay], callable_object, params) else @@targets_of_pending_timers.delete(self) end when SEL_CHORE if params[:repeat] FXApp.instance.addChore(callable_object, params) else @@targets_of_pending_chores.delete(self) end end result end end # class FXPseudoTarget end # module Fox # # The Responder2 module provides the #connect method, # which is mixed-in to all classes that have a message # target (i.e. Fox::FXDataTarget, Fox::FXRecentFiles # and Fox::FXWindow). # module Responder2 # # Assign a "handler" for all FOX messages of type _messageType_ # sent from this widget. When called with only one argument, # a block is expected, e.g. # # aButton.connect(SEL_COMMAND) { |sender, selector, data| # ... code to handle this event ... # } # # The arguments passed into the block are the _sender_ of the # message (i.e. the widget), the _selector_ for the message, and # any message-specific _data_. # # When #connect is called with two arguments, the second argument # should be some callable object such as a Method or Proc instance, e.g. # # aButton.connect(SEL_COMMAND, method(:onCommand)) # # As with the one-argument form of #connect, the callable object # will be "called" with three arguments (the sender, selector and # message data). # def connect(message_type, callable_object=nil, &block) unless instance_variables.include?('@pseudoTarget') || instance_variables.include?(:@pseudoTarget) @pseudoTarget = Fox::FXPseudoTarget.new self.target = @pseudoTarget end @pseudoTarget.pconnect(message_type, callable_object ? callable_object : block) end end module Fox class FXDataTarget include Responder2 end class FXRecentFiles include Responder2 end class FXWindow include Responder2 end end require 'fox16/timeout' require 'fox16/chore' require 'fox16/signal' require 'fox16/input' require 'fox16/accel_table'