# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.
# 
# Some parts are
# Copyright 2004-2007, wxRuby development team
# released under the MIT-like wxRuby2 license

# Adapted for wxRuby3
###

require 'wx'

module DragDrop

  # This sample demonstrates the use of the Clipboard and Drag and Drop
  # classes. Whilst the functionality of these is slightly different, they
  # are both based around the use of the DataObject classes to exchange
  # data of various sorts between applications (i.e. into and out of
  # wxRuby)

  # A ListBox that collects file names dropped onto it
  class FileDropList < Wx::ListBox
    def initialize(*args)
      super
      # Set the handler for drag and drop actions
      self.drop_target = ListFileDropTarget.new(self)
    end

    # The class that actually handles the dropped files; it keeps a
    # reference to the ListBox, and appends items as they are added
    class ListFileDropTarget < Wx::FileDropTarget
      def initialize(list)
        super()
        @list = list
      end

      # This method is overridden to specify what happens when a file is
      # dropped
      def on_drop_files(x, y, files)
        files.each { | file | @list.append(file) }
        true # currently need to return boolean from this method
      end
    end
  end

  class FileDropPane < Wx::Panel
    LABEL = "Drag and drop files from Explorer/Finder/etc to here\n" +
            "to add them to the list."
    def initialize(parent)
      super
      sizer = Wx::BoxSizer.new(Wx::VERTICAL)
      txt = Wx::StaticText.new( self, :label => LABEL)
      sizer.add(txt, 0, Wx::ALL, 4)

      @drop = FileDropList.new(self)
      sizer.add(@drop, 1, Wx::GROW|Wx::ALL, 4)
      self.sizer = sizer
    end
  end

  # A canvas which can display a pasted image
  class PasteCanvas < Wx::Window
    attr_accessor :bitmap
    def initialize(parent)
      super(parent, :style => Wx::SUNKEN_BORDER)
      self.size = [ 200, 200 ]
      @bitmap = Wx::NULL_BITMAP
      evt_paint :on_paint
    end

    def on_paint(evt)
      paint do | dc  |
        dc.clear
        if bitmap.ok?
          dc.draw_bitmap(bitmap, 0, 0, false)
        end
        dc.pen = Wx::BLACK_PEN
      end
    end
  end

  # A Notebook panel to hold an image-paste canvas
  class PastePane < Wx::Panel
    LABEL = "Use the buttons below to paste text and images from\n" +
            "the system clipboard, and then to copy them back."
    def initialize(parent)
      super
      sizer = Wx::BoxSizer.new(Wx::VERTICAL)
      txt = Wx::StaticText.new( self, :label => LABEL)
      sizer.add(txt, 0, Wx::ALL, 4)

      # Sizer for displaying text and image from the clipboard
      paste_sizer = Wx::FlexGridSizer.new(2, 2, 2, 2)
      paste_sizer.add_growable_col(0, 1)
      paste_sizer.add_growable_col(1, 1)
      paste_sizer.add_growable_row(1)

      paste_sizer.add( Wx::StaticText.new(self, :label => 'Clipboard text') )
      paste_sizer.add( Wx::StaticText.new(self, :label => 'Clipboard image') )

      # Target for displaying text from the clipboard
      @text = Wx::TextCtrl.new(self, :style => Wx::TE_MULTILINE)
      paste_sizer.add(@text, 1, Wx::GROW)

      # Target for displaying images from the clipboard
      @canvas = PasteCanvas.new(self)
      paste_sizer.add(@canvas, 1, Wx::GROW)

      sizer.add(paste_sizer, 1, Wx::ALL|Wx::GROW, 4)

      button_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)

      @paste_bt    = Wx::Button.new(self, :label => 'Paste')
      evt_button @paste_bt, :on_paste
      button_sizer.add(@paste_bt, 0, Wx::ALL, 4)

      @copy_img_bt = Wx::Button.new(self, :label => 'Copy image')
      evt_button @copy_img_bt, :on_copy_image
      button_sizer.add(@copy_img_bt, 0, Wx::ALL, 4)

      @copy_txt_bt = Wx::Button.new(self, :label => 'Copy text')
      evt_button @copy_txt_bt, :on_copy_text
      button_sizer.add(@copy_txt_bt, 0, Wx::ALL, 4)

      sizer.add(button_sizer, 0)
      self.sizer = sizer
    end

    # Receive data from the clipboard
    def on_paste(evt)
      # Temporarily open the clipboard
      Wx::Clipboard.open do | clip |
        # Test if bitmap data is available on the clipboard; if so, copy
        if clip.supported?(Wx::DF_BITMAP)
          bmp = Wx::BitmapDataObject.new
          clip.get_data(bmp) # Fill the data object with bitmap`
          @canvas.bitmap = bmp.bitmap
          @canvas.refresh
        end
        # Test if text data is available on the clipboard; if so, copy
        if clip.supported?(Wx::DF_TEXT)
          txt = Wx::TextDataObject.new
          clip.get_data(txt) # Fill the data object with text
          @text.value = txt.text
        end
      end
    end

    # Paste an image to the clipboard
    def on_copy_image
      Wx::Clipboard.open do | clip |
        clip.data = Wx::BitmapDataObject.new(@canvas.bitmap)
      end
    end

    # Paste text to the clipboard
    def on_copy_text
      Wx::Clipboard.open do | clip |
        clip.data = Wx::TextDataObject.new(@text.value)
      end
    end
  end

  class DataObjectFrame < Wx::Frame
    def initialize(parent)
      super
      panel = Wx::Panel.new(self)
      panel.sizer = Wx::BoxSizer.new(Wx::VERTICAL)
      nb = Wx::Notebook.new(panel)
      panel.sizer.add(nb, 1, Wx::ALL|Wx::GROW, 8)
      fd = FileDropPane.new(nb)
      nb.add_page(fd, 'Drag and Drop')
      cv = PastePane.new(nb)
      nb.add_page(cv, 'Clipboard')
      # urldrop = URLDropList.new(self)
    end
  end

end

module DragDropSample

  include WxRuby::Sample if defined? WxRuby::Sample

  def self.describe
    { file: __FILE__,
      summary: 'wxRuby Drag&Drop example.',
      description: <<~__TXT
        wxRuby example demonstrating the use of the Clipboard and Drag and Drop
        classes. Whilst the functionality of these is slightly different, they
        are both based around the use of the DataObject classes to exchange
        data of various sorts between applications (i.e. into and out of
        wxRuby).
        __TXT
    }
  end

  def self.activate
    frame = DragDrop::DataObjectFrame.new(nil)
    frame.show
    frame
  end

  if $0 == __FILE__
    Wx::App.run { DragDropSample.activate }
  end

end
