Putting It All Together
Prev | Chapter 3. Drag and Drop | Next

## Putting It All Together

We've studied drag-and-drop enabled applications from two points of view, that of a drag source and that of a drop site. But for most applications, you'll want a window to act as both a drag source and a drop site. As it turns out, this is just a simple combination of the techniques we've already seen in the previous sections.

If we use our completed drag source example program from the previous section as a starting point, and then compare it to the drop site example from the first section, it is apparent that the only "pieces" missing are:

- A call to `dropEnable()`, to make `DragSource`'s canvas drop-enabled;

- A handler for the `SEL_DND_MOTION` message; and,

- A handler for the `SEL_DND_DROP` message.

If you merge those three short bits of code from `dropsite.rb` into `dragsource.rb`, you should end up with a program that can act as both a drag source and a drop site. To test this program, you should be able to start up two separate copies side-by-side and then drag from one to the other. Since, as written, both copies will start up with a red background, you might want to modify one of them to have a different initial backgroud color. Another interesting possibility is to start up a third program (such as an FXRuby example that has displays a color dialog) and drag colors back and forth between all three programs. You could spend days doing this and never leave the house.

The complete program is listed below, and is included in the `examples` directory under the file name `dragdrop.rb`.

    require 'fox'

    include Fox

    class DragDropWindow < FXMainWindow
      def initialize(anApp)
        # Initialize base class
        super(anApp, "Drag and Drop", nil, nil, DECOR_ALL, 0, 0, 400, 300)

        # Fill main window with canvas
        @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y)
        @canvas.backColor = "red"

        # Enable canvas for drag-and-drop messages
        @canvas.dropEnable

        # Handle expose events on the canvas
        @canvas.connect(SEL_PAINT) { |sender, sel, event|
          FXDCWindow.new(@canvas, event) { |dc|
            dc.foreground = @canvas.backColor
            dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h)
          }
        }

        # Handle left button press
        @canvas.connect(SEL_LEFTBUTTONPRESS) {
          #
          # Capture (grab) the mouse when the button goes down, so that all future
          # mouse events will be reported to this widget, even if those events occur
          # outside of this widget.
          #
          @canvas.grab

          # Advertise which drag types we can offer
          dragTypes = [FXWindow.colorType]
          @canvas.beginDrag(dragTypes)
        }

        # Handle mouse motion events
        @canvas.connect(SEL_MOTION) { |sender, sel, event|
          if @canvas.dragging?
            @canvas.handleDrag(event.root_x, event.root_y)
            unless @canvas.didAccept == DRAG_REJECT
              @canvas.dragCursor = getApp().getDefaultCursor(DEF_SWATCH_CURSOR)
            else
              @canvas.dragCursor = getApp().getDefaultCursor(DEF_DNDSTOP_CURSOR)
            end
          end
        }

        # Handle SEL_DND_MOTION messages from the canvas
        @canvas.connect(SEL_DND_MOTION) {
          if @canvas.offeredDNDType?(FROM_DRAGNDROP, FXWindow.colorType)
            @canvas.acceptDrop
          end
        }

        # Handle left button release
        @canvas.connect(SEL_LEFTBUTTONRELEASE) {
          @canvas.ungrab
          @canvas.endDrag
        }

        # Handle SEL_DND_DROP message from the canvas
        @canvas.connect(SEL_DND_DROP) {
          # Try to obtain the data as color values first
          data = @canvas.getDNDData(FROM_DRAGNDROP, FXWindow.colorType)
          unless data.nil?
            # Update canvas background color
            @canvas.backColor = Fox.fxdecodeColorData(data)
          end
        }

        # Handle request for DND data
        @canvas.connect(SEL_DND_REQUEST) { |sender, sel, event|
          if event.target == FXWindow.colorType
            @canvas.setDNDData(FROM_DRAGNDROP, FXWindow.colorType, Fox.fxencodeColorData(@canvas.backColor))
          end
        }
      end

      def create
        # Create the main window and canvas
        super

        # Register the drag type for colors
        FXWindow.colorType = getApp().registerDragType(FXWindow.colorTypeName)

        # Show the main window
        show(PLACEMENT_SCREEN)
      end
    end

    if __FILE__ == $0
      FXApp.new("DragDrop", "FXRuby") do |theApp|
        DragDropWindow.new(theApp)
        theApp.create
        theApp.run
      end
    end

Prev | Up | Next
Drag Sources | Home | Chapter 4. Examples