How can I get the event when material dropped on Face

You could use a hybrid observer class, that watches the tool stack (for each model as it is opened,) then when the PaintTool is activated, attaches itself to watch the active entities and the materials collection.

It will not attach to the open model if loaded into the console, so load a new model.
Also, it may need to some tweaking to work on a Mac with multiple models open.

paint_spy.rb (3.2 KB)

which looks like this for those not wishing to d/l the file:


module SomeAuthor
  module SomePlugin
  
    @@loaded ||= false
    @@spy ||= false
    
    def self.spy
      @@spy
    end

    # This is an example of a hybrid observer that watches the tools collection
    # for PaintTool activation, then attaches itself as an obsever to watch the
    # materials collection and the active entities context.
    # It will set instance references to the modified entity and it's material.
    # When the active tool is changed and is no longer the PianTool, then this
    # hybrid observer will stop watching the materials collection and entities.
    class HybridSpy < Sketchup::EntitiesObserver

      # Construction:
      attr_reader( :material_used, :back_material_used, :painted_entity )

      def initialize(*args)
        reset()
        @previous_tool  = nil
      end

      def reset
        @back_material_used = nil
        @material_used  = nil
        @painted_entity = nil
      end

      def watch_tools(model)
        model.tools.add_observer(self)
        puts "Spy now watching Tools collection of active model:\n  #{model.inspect}\n"
      end

      # AppObserver callbacks:
      def expectsStartupModelNotifications
        return true
      end
      def onNewModel(model)
        watch_tools(model)
      end
      def onOpenModel(model)
        watch_tools(model)
      end

      # ToolsObserver callbacks:
      def onActiveToolChanged(tools, tool_name, tool_id)
        model = tools.model
        if tool_id == 21074 # PaintTool
          @previous_tool = 21074
          puts "\nPaintTool activated"
          # Begin watching the materials & active entities collections:
          model.materials.add_observer(self)
          model.active_entities.add_observer(self)
        elsif @previous_tool == 21074
          puts "\nPaintTool deactivated"
          # Stop watching the materials & active entities collections:
          model.materials.remove_observer(self)
          model.active_entities.remove_observer(self)
          @previous_tool = tool_id
          reset() # reset the instance vars to nil
        end
      end

      # EntitiesObserver callbacks:
      def onElementModified(entities, entity)
        return unless entity.is_a?(Sketchup::Drawingelement)
        puts "\nonElementModified: #{entity}"
        @painted_entity = entity
        if entity.respond_to?(:material)
          puts "  front material: #{entity.material.inspect}"
          puts "  material name : #{entity.material.name}" unless entity.material.nil?
          @material_used = entity.material
        else
          @material_used = nil
        end
        if entity.respond_to?(:back_material)
          puts "  back material : #{entity.back_material.inspect}"
          puts "  material name : #{entity.back_material.name}" unless entity.back_material.nil?
          @back_material_used = entity.material
        else
          @back_material_used = nil
        end
        #
        ### Notify some other code object of paint action ?
        #
      end

    end # class HybridSpy

    if !@@loaded
      # Attach as an AppObserver:
      @@spy = HybridSpy.new
      Sketchup.add_observer(@@spy)
      @@loaded = true
    end

  end
end
3 Likes