Example: Drag & Drop

Stephan
2006-07-27
2013-04-08
  • Stephan

    Stephan - 2006-07-27

    Hi!

    I liked to add Drag & Drop for files to my application. I think you belive I have had modified smartwin again ;) You are right! I add the following function to WidgetModalDialog.h:

            /// Setup Drag & Drop for this dialog
            /** This setup the ability to receive an WM_DROPFILES msg if you drop a file on dialog
              */
            void setDragAcceptFiles(bool accept = true);

        template< class Parent, class WidgetMessageMapType >
        void WidgetModalDialog< Parent, WidgetMessageMapType >::setDragAcceptFiles(bool accept)
        {
            DragAcceptFiles(this->handle(),accept);
        }

    Now, here is my example code. I use a resource dialog, because a haven't enough time to create a hard coded dialog:

    /*!
      \file Main.cpp
      \brief Example application demonstrating useing of Drag & Drop on modal dialogs.

      I just add the function to WidgetModalDialog, but you can use it on normal dialogs, too.
    */
    #include "SmartWin.h"
    #include "resource.h"

    using namespace SmartWin;

    class WidgetTest1
        : public WidgetFactory<WidgetModalDialog, WidgetTest1, ModalDialogWidget>
    {
    public:
        WidgetTest1( Widget * parent )
            : Widget( parent )
        {
            onInitDialog( &WidgetTest1::initDialog );    // Mandatory
        }

        ~WidgetTest1()
        {
        }

    private:
        WidgetButtonPtr itsOkButton;

        // Needed to allow the Widgets to be subclassed before the dialog appears,
        // but after the dialog is created.
        bool initDialog()
        {
            setDragAcceptFiles(true);    //This function enables Drag & Drop

            onRaw(&WidgetTest1::OnDropFiles, SmartWin::Message(WM_DROPFILES));

            setText( _T("A modal dialog with Drag & Drop support") );
            itsOkButton = subclassButton( IDOK );
            itsOkButton->onClicked( &WidgetTest1::ok_clicked );
            return false;
        }

        HRESULT OnDropFiles(LPARAM lParam, WPARAM wParam)
        {
            HDROP m_hDropInfo = (HDROP)wParam;
            if (m_hDropInfo) {
                int iFiles = DragQueryFile(m_hDropInfo, (UINT)-1, NULL, 0);
                TCHAR pFilename[MAX_PATH];
                DragQueryFile(m_hDropInfo, 0, pFilename, _MAX_PATH);
                setText(pFilename);
                DragFinish(m_hDropInfo);
            }
            m_hDropInfo = 0;
            return 0;
        }

        void ok_clicked( WidgetButtonPtr btn )
        {
            endDialog( IDOK );    // IDOK or IDCANCEL or any other value.
        }

        // This one kicks in ONLY if user presses the cross in the upper right corner...
    };

    int SmartWinMain( Application & app )
    {
        WidgetTest1 test( NULL );
        int res = test.createDialog(IDD_DIALOG1); // Blocks until the dialog is finished.
        return app.run();
    }

    Enjoy it!

     
    • Nobody/Anonymous

      Great! :)
      You're really productive!!
      This time you've also mostly 99% followed the coding standard so this time it's easy to incorporate your code into the lib...

      I'm gonna priotitize trying to get your code bended into the library when I start on my project within a few months...

      .t

       
      • Stephan

        Stephan - 2006-08-01

        I'm happy that you like my code this time :)

        Maybe it's possible to create an own "event", because you like to make it easy (something like onDropFile or onDragDrop).

         
        • Thomas Hansen

          Thomas Hansen - 2006-08-03

          The PERFECT way to do this would probably be to create a "drag'n'drop" Aspect called e.g. "AspectDragDrop" and include it through inheritance to the relevant widgets (I figure probably like WidgetWindowBase and (maybe) WidgetTextBox or something....??)

          Or...??

          .t

           
          • Stephan

            Stephan - 2006-08-05

            You like to have "AspectDragDrop"? No problem!

            AspectDragDrop.h:

            // $Revision: 1.15 $
            /*
              Copyright (c) 2006, Stephan Schweig
              All rights reserved.

              Redistribution and use in source and binary forms, with or without modification,
              are permitted provided that the following conditions are met:

                  * Redistributions of source code must retain the above copyright notice,
                    this list of conditions and the following disclaimer.
                  * Redistributions in binary form must reproduce the above copyright notice,
                    this list of conditions and the following disclaimer in the documentation
                    and/or other materials provided with the distribution.
                  * Neither the name of the SmartWin++ nor the names of its contributors
                    may be used to endorse or promote products derived from this software
                    without specific prior written permission.

              THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
              ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
              WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
              IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
              INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
              (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
              LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
              ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
              OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
              OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
            */
            #ifndef AspectDragDrop_h
            #define AspectDragDrop_h

            #include "boost.h"
            #include "../SignalParams.h"

            namespace SmartWin
            {
            // begin namespace SmartWin

            // Dispatcher class with specializations for dispatching event to event handlers of
            // the AspectDragDrop
            template< class EventHandlerClass, class WidgetType, class MessageMapType, bool IsControl >
            class AspectDragDropDispatcher
            {
            };

            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            class AspectDragDropDispatcher<EventHandlerClass, WidgetType, MessageMapType, true/*Control Widget*/>
            {
            public:
                static HRESULT dispatch( private_::SignalContent & params )
                {
                    typename MessageMapType::voidFunctionTakingHdrop func =
                        reinterpret_cast< typename MessageMapType::voidFunctionTakingHdrop >( params.Function );

                    EventHandlerClass * ThisParent = internal_::getTypedParentOrThrow < EventHandlerClass * >( params.This );
                    WidgetType * This = boost::polymorphic_cast< WidgetType * >( params.This );

                    func( ThisParent,
                        This,
                        (HDROP)( params.Msg.WParam )
                        );

                    params.RunDefaultHandling = true;
                    return 0;
                }

                static HRESULT dispatchThis( private_::SignalContent & params )
                {
                    typename MessageMapType::itsVoidFunctionTakingHdrop func =
                        reinterpret_cast< typename MessageMapType::itsVoidFunctionTakingHdrop >( params.FunctionThis );

                    EventHandlerClass * ThisParent = internal_::getTypedParentOrThrow < EventHandlerClass * >( params.This );
                    WidgetType * This = boost::polymorphic_cast< WidgetType * >( params.This );

                    ( ( * ThisParent ).*func )(
                        This,
                        (HDROP)( params.Msg.WParam )
                        );

                    params.RunDefaultHandling = true;
                    return 0;
                }
            };

            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            class AspectDragDropDispatcher<EventHandlerClass, WidgetType, MessageMapType, false/*Container Widget*/>
            {
            public:
                static HRESULT dispatch( private_::SignalContent & params )
                {
                    typename MessageMapType::boolFunctionTakingInt func =
                        reinterpret_cast< typename MessageMapType::voidFunctionTakingHdrop >( params.Function );

                    EventHandlerClass * ThisParent = internal_::getTypedParentOrThrow < EventHandlerClass * >( params.This );

                    func(
                        ThisParent,
                        (HDROP)( params.Msg.WParam )
                        );

                    params.RunDefaultHandling = true;
                    return 0;
                }

                static HRESULT dispatchThis( private_::SignalContent & params )
                {
                    typename MessageMapType::itsVoidFunctionTakingHdrop func =
                        reinterpret_cast< typename MessageMapType::itsVoidFunctionTakingHdrop >( params.FunctionThis );

                    EventHandlerClass * ThisParent = internal_::getTypedParentOrThrow < EventHandlerClass * >( params.This );

                    ( ( * ThisParent ).*func )(
                        (HDROP)( params.Msg.WParam )
                        );

                    params.RunDefaultHandling = true;
                    return 0;
                }
            };

            /// Aspect class used by dialog Widgets that have the possibility of trapping "drop files events".
            /** \ingroup AspectClasses
              * E.g. the WidgetModalDialog can trap "drop files events" therefore they realize the AspectDragDrop through inheritance.
              */
            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            class AspectDragDrop
            {
                typedef AspectDragDropDispatcher< EventHandlerClass, WidgetType, MessageMapType, MessageMapType::IsControl > Dispatcher;

            public:
                /// \ingroup EventHandlersAspectAspectDragDrop
                /// Setting the event handler for the "drop files" event
                /** If supplied event handler is called when a file is dropped over the widget <br>
                  *
                  * Example:
                  *
                  * void DropFiles(HDROP m_hDropInfo)
                  * {
                  *     if (m_hDropInfo) {
                  *         int iFiles = DragQueryFile(m_hDropInfo, (UINT)-1, NULL, 0);
                  *         char pFilename[MAX_PATH];
                  *         DragQueryFile(m_hDropInfo, 0, pFilename, MAX_PATH);
                  *         setText(pFilename);
                  *         DragFinish(m_hDropInfo);
                  *     }
                  *     m_hDropInfo = 0;
                  * }
                  */
                void onDragDrop( typename MessageMapType::itsVoidFunctionTakingHdrop eventHandler );
                void onDragDrop( typename MessageMapType::voidFunctionTakingHdrop eventHandler );

                /// Setup Drag & Drop for this dialog
                /** This setup the ability to receive an WM_DROPFILES msg if you drop a file on dialog
                */
                void setDragAcceptFiles(bool accept = true);

            protected:
                virtual ~AspectDragDrop()
                {}
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Implementation of class
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            void AspectDragDrop< EventHandlerClass, WidgetType, MessageMapType >::onDragDrop( typename MessageMapType::itsVoidFunctionTakingHdrop eventHandler )
            {
                MessageMapType * ptrThis = boost::polymorphic_cast< MessageMapType * >( this );
                ptrThis->addNewSignal(
                    typename MessageMapType::SignalTupleType(
                        private_::SignalContent(
                            Message( WM_DROPFILES ),
                            reinterpret_cast< itsVoidFunction >( eventHandler ),
                            ptrThis
                        ),
                        typename MessageMapType::SignalType(
                            typename MessageMapType::SignalType::SlotType( & Dispatcher::dispatchThis ) )
                    )
                );
            }

            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            void AspectDragDrop< EventHandlerClass, WidgetType, MessageMapType >::onDragDrop( typename MessageMapType::voidFunctionTakingHdrop eventHandler )
            {
                MessageMapType * ptrThis = boost::polymorphic_cast< MessageMapType * >( this );
                ptrThis->addNewSignal(
                    typename MessageMapType::SignalTupleType(
                        private_::SignalContent(
                            Message( WM_DROPFILES ),
                            reinterpret_cast< private_::SignalContent::voidFunctionTakingVoid >( eventHandler ),
                            ptrThis
                        ),
                        typename MessageMapType::SignalType(
                            MessageMapType::SignalType::SlotType( & Dispatcher::dispatch )
                        )
                    )
                );
            }

            template< class EventHandlerClass, class WidgetType, class MessageMapType >
            void AspectDragDrop< EventHandlerClass, WidgetType, MessageMapType >::setDragAcceptFiles(bool accept)
            {
                DragAcceptFiles(static_cast< WidgetType * >( this )->handle(),accept);
            }

            // end namespace SmartWin
            }

            #endif

            MessageMap.h:

                  /// \ingroup eventsSignatures
                /// Typedef of a member function to the original class taking HDROP returning void
                typedef void ( EventHandlerClass::* itsVoidFunctionTakingHdrop )( HDROP );

                /// \ingroup eventsSignatures
                /// Typedef of a static/global function taking a pointer to the original class and one HDROP returning void
                typedef void ( * voidFunctionTakingHdrop )( EventHandlerClass *, HDROP );

            WidgetWindowBase.h:

            - Add AspectDragDrop header:
            #include "../aspects/AspectDragDrop.h"

            - Add aspect to class:
                public AspectDragDrop< EventHandlerClass, WidgetWindowBase< EventHandlerClass, MessageMapPolicy >, MessageMap< EventHandlerClass, MessageMapPolicy > >,

             
            • Stephan

              Stephan - 2006-08-05

              Example:

              #include "SmartWin.h"
              using namespace SmartWin;

              class DragDropTest
                          : public WidgetFactory< WidgetWindow, DragDropTest >
              {

              public:

                  void DropFile(HDROP handle)
                  {
                      if (handle) {
                          int iFiles = DragQueryFile(handle, (UINT)-1, NULL, 0);
                          char pFilename[MAX_PATH];
                          DragQueryFile(handle, 0, pFilename, _MAX_PATH);
                          setText(pFilename);
                          DragFinish(handle);
                      }
                      handle = 0;
                  }

                  void initAndCreate()
                  {
                      createWindow();
                      setText( _T( "Hello SmartWin" ) ); // Title

                      SmartWin::Rectangle desktop( getDesktopSize() );
                      setBounds( desktop.top( 0.2 ).left( 0.3 ) );

                      setDragAcceptFiles( true );    //Initialise Drag & Drop
                      onDragDrop( &DragDropTest::DropFile );    //Set Drop-Callback-Function
                  }

              };

              int SmartWinMain( Application & app )
              {
                  DragDropTest * testHello = new DragDropTest;
                  testHello->initAndCreate();
                  return app.run();
              }

               
              • Stephan

                Stephan - 2006-09-01

                Hm... What's wrong with my code now? I created an Drag-Drop-Aspekt as you want! But, no comments and no changes on CSV.

                 
                • Thomas Hansen

                  Thomas Hansen - 2006-09-01

                  Howdy Stephens, I haven't had the time to look into this just yet...
                  Send me the file(s) on email (polterguy _at_ gmail dot com) and I'll incorporate them into SmartWin++...
                  :)

                  Preferable also sample code (as you did in your earlier posting)

                  .t

                   
    • andrew7

      andrew7 - 2006-11-30

      Yes, the AspectDragDrop.h did make into the CVS eventually.

       

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks