module Tk
  # Translation from Tcl: http://wiki.tcl.tk/1954
  class Tooltip < Struct.new(:text, :tooltip)
    def bind_to(widget)
      widget.bind('<Any-Enter>'   ){ Tk::After.ms(500){ show(widget) }}
      widget.bind('<Any-Leave>'   ){ Tk::After.ms(500){ destroy }}
      widget.bind('<Any-KeyPress>'){ Tk::After.ms(500){ destroy }}
      widget.bind('<Any-Button>'  ){ Tk::After.ms(500){ destroy }}
    end

    def destroy
      tooltip.destroy
    rescue NoMethodError, RuntimeError => ex
    end

    def show_on(widget)
      root = Tk.root
      root_pointerx, root_pointery = root.winfo_pointerx, root.winfo_pointery
      return unless Tk::Winfo.containing(root_pointerx, root_pointery)

      destroy

      scrh, scrw = widget.winfo_screenheight, widget.winfo_screenwidth

      self.tooltip = tooltip = Tk::Toplevel.new(widget, bd: true, bg: 'black')
      tooltip.wm_geometry = "+#{scrh}+#{scrw}"
      tooltip.wm_overrideredirect = true
      tooltip.attributes(topmost: true) if tooltip.tk_windowingsystem == :win32

      label = Tk::Label.new(tooltip, bg: :lightyellow, fg: :black,
                                     text: text, justify: :left).pack

      width, height = label.winfo_reqwidth, label.winfo_reqheight

      position_x, position_y = root_pointerx, root_pointery + 25
      root_screen_width = root.winfo_screenwidth

      if (position_x + width) > root_screen_width
        position_x -= ((position_x + width) - root_screen_width)
      end

      tooltip.wm_geometry = "#{width}x#{height}+#{position_x}+#{position_y}"
      tooltip.raise

      tooltip.bind('Any-Enter'){ destroy }
      tooltip.bind('Any-Leave'){ destroy }
    end
  end
end

if __FILE__ == $0
  require 'ffi-tk'

  button = Tk::Button.new(text: 'hello').pack
  tooltip = Tk::Tooltip.new('Hello, World!')
  tooltip.bind_to(button)

  Tk.mainloop
end