Search code examples
rubymouse-cursorsketchup

How to create and set a custom cursor in SketchUp Ruby


I am creating a custom tool in SketchUp Ruby and would like to be able to set custom cursors to help the user identify which tool they're using. Below is the current code I have incase you would like to see what I have so far.

#Some presets
system "clear"
model = Sketchup.active_model
entities = model.active_entities
selection=Sketchup.active_model.selection
materials=Sketchup.active_model.materials
layer_array=Sketchup.active_model.layers

module Examples
  module CustomTool

    class LineTool

      def activate
    @mouse_ip = Sketchup::InputPoint.new
        @picked_first_ip = Sketchup::InputPoint.new
    #num = "2"
    #UI.messagebox((num))
        update_ui
      end

      def deactivate(view)
        view.invalidate
      end

      def resume(view)
        update_ui
        view.invalidate
      end

      def suspend(view)
        view.invalidate
      end

      def onCancel(reason, view)
        reset_tool
        view.invalidate
      end

      def onMouseMove(flags, x, y, view)
        if picked_first_point?
          @mouse_ip.pick(view, x, y, @picked_first_ip)
      UI.messagebox("One")
        else
          @mouse_ip.pick(view, x, y)
      UI.messagebox("Two")
        end
        view.tooltip = @mouse_ip.tooltip if @mouse_ip.valid?
        view.invalidate
      end

      def onLButtonDown(flags, x, y, view)
        if picked_first_point? && create_edge > 0
          reset_tool
        else
          @picked_first_ip.copy!(@mouse_ip)
      #UI.messagebox("Test")
        end
        update_ui
        view.invalidate
      end

      #CURSOR_PENCIL = 641
      #def onSetCursor
        #UI.set_cursor(CURSOR_PENCIL)
      #end

       cursor_id = nil
       cursor_path = Sketchup.find_support_file("Pointer.png", "Plugins")
       if cursor_path
         cursor_id = UI.create_cursor(cursor_path, 0, 0)
       end

       def onSetCursor
         UI.set_cursor(cursor_id)
       end

    end # class LineTool

    def self.activate_line_tool
      Sketchup.active_model.select_tool(LineTool.new)
    end

    unless file_loaded?(__FILE__)
      menu = UI.menu('Plugins')
      menu.add_item('Darrian\'s Point Maker Tool') {
        self.activate_line_tool
      }
      file_loaded(__FILE__)
    end

  end # module CustomTool
end # module Examples

This originally came from an example on github where a kind user was demonstrating how to create custom tools. I tried to add a spin to it but have gotten myself entangled severely. The bit of code I would like to focus on however, is this piece shown below...

   cursor_id = nil
   cursor_path = Sketchup.find_support_file("Pointer.png", "Plugins")
   if cursor_path
     cursor_id = UI.create_cursor(cursor_path, 0, 0)
   end

   def onSetCursor
     UI.set_cursor(cursor_id)
   end

With this section of code, I am trying to set the custom cursor to 'Pointer.png'. The image is in the plugins folder on my computer, I have an image to verify that.

https://i.sstatic.net/6aGGD.png

When I run the full code, I get an additional tool being added to my extensions tab at the top of my SketchUp window named, "Darrian's Point Maker Tool". When I click on this tool, I would expect the cursor to change to the image that is on 'Pointer.png'. Instead however, it stays as a white arrow cursor.

If you're curious, the image is a diamond sword from minecraft (I'm in a experimenting phase at the moment). I got the image from here...

https://minecraft.fandom.com/wiki/Sword

What is the problem I am facing and how can I correct it?


Solution

  • Your example code uses PNG file format for your cursor graphic, and that is ok, but I recommend using vector graphics instead.

    In the future, SketchUp will adopt SVG format on both 'Mac' and 'Windows'. But, as of today we developers need to use PDF for Mac and SVG for Windows.

    I changed the icon path to be relative to your '.rb' file, and not the Plugins folder path.

    It is recommended to create a folder and add your assets inside. I did not include this in the 'Possible solution' code example below.

                    Plugins Folder 
                           ↓
         _____________________________________
         ↓                                   ↓
    set-cursor.rb                        (Folder)
                                        set-cursor
                                             ↓
                                          (Folder)
                                           assets
                                             ↓
                          _______________________________________
                          ↓                  ↓                  ↓
                       (Folder)           (Folder)           (Folder)
                         pdf                svg                png
                          ↓                  ↓                  ↓
                      Pointer.pdf       Pointer.svg        Pointer.png
    
    # Example on how to get cursor path for PNG format
    # If you follow the file structure in the above example.
    # -------------------------------------------------------
    # Finds path relative to your ruby script file.
    path = File.dirname(__FILE__)
    cursor_path = File.join(path, 'set-cursor/assets/png/Pointer.png')
    

    Also, when calling the following UI.create_cursor(cursor_path, 8, 0) make sure you tweak the parameter values for x,y to work well with the cursor graphic.

    Possible Solution:

    How to test code below:

    1. Create .rb file (name it 'set-cursor.rb' for example) and copy & paste the code below. Then place the file in the SketchUp Plugins folder.
    2. Activate the tool inside Sketchup by going to Plugins or Extension Menu -> Darrian's Point Maker Tool
    3. Done! If you have a PNG file named 'Pointer.png' inside the plugins folder then this script will create a cursor.
    module Examples
      module CustomTool
        MAC = RUBY_PLATFORM =~ /(darwin)/i ? true : false
        WIN = RUBY_PLATFORM =~ /(mswin|mingw)/i ? true : false
        class LineTool
          def activate
            # Using PDF format for Mac and SVG format for Windows.
            if MAC
              icon_format = '.pdf'
            else
              icon_format = '.svg'
            end
            # Option for use Vector graphics for the icon.
            cursor_name = "Pointer#{icon_format}"
            # OR use PNG, but I recomend using PDF for MAC & SVG for Windows.
            cursor_name = 'Pointer.png'
            # Finds path relative to your ruby script file.
            path = File.dirname(__FILE__)
            # Pointer.png needs to be in same path as your .rb file
            cursor_path = File.join(path, cursor_name)
            @result = File.file?(cursor_path)
            unless @result
              msg = "Can't find the 'cursor icon' path"
              UI.messagebox(msg, MB_OK)
              return
            end
    
            # ----------------------------------------------------------------------
            # The create_cursor method is used to create a cursor from an image
            # file at the specified location. This must be called from within a
            # custom Tool.
            # ----------------------------------------------------------------------
            # Since SketchUp 2016 it is possible to provide vector images
            # for the cursors. SVG format for Windows and PDF format for OS X.
            # ----------------------------------------------------------------------
            # .create_cursor(filename, hot_x, hot_y) # => Integer
    
            @cursor_id = UI.create_cursor(cursor_path, 8, 0)
          end
    
          def onSetCursor
            # ----------------------------------------------------------------------
            # The 'set_cursor' method is used to change the cursor to a new cursor
            # with a given cursor id. See UI.create_cursor and the Tool class for
            # details on creating your own tools with arbitrary cursors.
    
            UI.set_cursor(@cursor_id) if @result
          end
          # # #
        end # class LineTool
        unless defined?(@loaded)
          UI.menu('Plugins').add_item('Darrian\'s Point Maker Tool') do
            Sketchup.active_model.select_tool(Examples::CustomTool::LineTool.new)
          end
          @loaded = true
        end
      end # module CustomTool
    end # module Examples