| 1 | Drag-and-Drop Support in wxWindows |
| 2 | ================================== |
| 3 | |
| 4 | 1. Overview |
| 5 | -------- |
| 6 | |
| 7 | a) What is it? |
| 8 | |
| 9 | We're calling drag-and-drop (or d&d for short) the OLE mechanism of data |
| 10 | transfer. Please note that it's not the same thing as the file oriented d&d |
| 11 | of Windows 3.1 "File Manager" which is designed for and limited to the file |
| 12 | names only. |
| 13 | |
| 14 | OLE d&d allows application to transfer data of any type to the same or |
| 15 | another process. |
| 16 | |
| 17 | |
| 18 | b) How is it done? (user's point of view) |
| 19 | |
| 20 | To start a d&d operation the user presses the mouse button 1 (left) and |
| 21 | drags the selected object to another window (which must be at least partially |
| 22 | visible on the screen) or to an icon on the taskbar in which case the |
| 23 | corresponding window will be automatically restored. To finish the operation, |
| 24 | the user releases the button. Default d&d operation is "move", but several key |
| 25 | act as modifiers: keeping down the <Ctrl> key at the moment of drop does |
| 26 | "copy", while <Shift> or <Alt> force the "move" (makes sense if default isn't |
| 27 | "move"). |
| 28 | |
| 29 | |
| 30 | c) How is it done? (programmer's point of view) |
| 31 | |
| 32 | There are several objects participating in a d&d operation. First of all, |
| 33 | there is the data object itself. Second, there is the drop source which is |
| 34 | responsible for creating the data object (if it doesn't exist yet) and starting |
| 35 | the d&d operation. Finally, the drop target recieves the notification when |
| 36 | the data is dropped onto the associated window (see below) and is responsible |
| 37 | for pasting the data and returning the result code (copy, move or failure). |
| 38 | There is one class for each one of these roles in wxWindows d&d implementation, |
| 39 | plese see their descriptions below for details. |
| 40 | |
| 41 | |
| 42 | |
| 43 | 2. Drop Target |
| 44 | ----------- |
| 45 | |
| 46 | a) Being a drop target |
| 47 | |
| 48 | ... is as easy as deriving your window class from wxDropTarget and |
| 49 | associating it with a wxWindow object (or perhaps some wxWindow-derived class, |
| 50 | such as wxFrame). The pure virtual function wxDropTarget::OnDrop() must be |
| 51 | implemented in your application and will be called whenever the mouse button |
| 52 | is released over the window in question. Other virtual functions that will be |
| 53 | called in the process of the d&d operation are OnEnter and OnLeave. |
| 54 | |
| 55 | @@ should OnDragOver() be user overridable also? |
| 56 | |
| 57 | You should associate wxDropTarget and wxWindow calling SetDropTarget: |
| 58 | wxWindow *pWindow = GetTopWindow(); |
| 59 | pWindow->SetDropTarget(new MyDropTarget); |
| 60 | |
| 61 | The object created passed to SetDropTarget becomes the propriety of wxWindow |
| 62 | and will be deleted with the window (or when you call SetDropTarget next |
| 63 | time). You can always break the association by calling SetDropTarget(NULL). |
| 64 | |
| 65 | When some data is dragged over a window, the program must decide if it's |
| 66 | going to accept this data or not. The virtual function IsAcceptedData() is |
| 67 | called to do it. The default implementation takes care of OLE interface |
| 68 | pointer manipulations and only requires you to override GetCountFormats() |
| 69 | and GetFormat(n) functions to let it know what data formats you support. |
| 70 | If it's not flexible enough for your application (i.e. the set of supported |
| 71 | formats changes over time...), you should override IsAcceptedData(). In 99% |
| 72 | of cases the default implementation is ok and you only have to return count |
| 73 | of supported formats (CF_xxx constants or one of your custom formats which |
| 74 | must have been registered) and their values. |
| 75 | |
| 76 | b) OnDrop(long x, long y, const void *pData) |
| 77 | |
| 78 | (x, y) are drop point (client) coordinates, pData is the pointer to data |
| 79 | (whatever it is). |
| 80 | |
| 81 | If 'true' is returned from OnDrop, the operation is considered to be |
| 82 | successful and the corresponding code (MOVE or COPY depending on the |
| 83 | keyboard control keys) is returned. Otherwise, the operation is cancelled. |
| 84 | |
| 85 | Please remember that returning 'true' here may mean 'move' and so the |
| 86 | drop source will delete the corresponding data - which would lead to |
| 87 | data loss if you didn't paste it properly. |
| 88 | |
| 89 | c) OnEnter() |
| 90 | |
| 91 | called when the mouse enters the window: you might use this function to |
| 92 | give some additional visual feedback. |
| 93 | |
| 94 | d) OnLeave() |
| 95 | |
| 96 | called when the mouse leaves the window; might be a good place to clean |
| 97 | up things allocated in OnEnter. |
| 98 | |
| 99 | e) Simple wxDropTarget specializations |
| 100 | |
| 101 | Two (very simple) wxDropTarget-derived classes are provided for two most |
| 102 | common situations: d&d of text and file d&d. To use them you only need to |
| 103 | override one virtual function OnDropText in wxTextDropTarget's case and |
| 104 | OnDropFiles for wxFileDropTarget. |
| 105 | |
| 106 | The (x, y) are the same as for OnDrop() function. OnDropText's last |
| 107 | parameter points to a (always ANSI, not Unicode) text string, while |
| 108 | OnDropFiles() parameter is the array of file names just dropped (and the |
| 109 | count of them is passed in the 3rd parameter). |
| 110 | |
| 111 | 3. Data Object |
| 112 | ----------- |
| 113 | |
| 114 | a) Drag and drop and clipboard |
| 115 | |
| 116 | The effect of a d&d operation is the same as using the clipboard to |
| 117 | cut/copy and paste data and it would be nice to use the same code to implement |
| 118 | these two data transfer mechanisms. The wxDataObject allows you to do exactly |
| 119 | this. It encapsulates the data which can be passed either through the clipboard |
| 120 | or d&d. |
| 121 | |
| 122 | |
| 123 | b) Data format |
| 124 | |
| 125 | There are several standard clipboard formats, such as text, bitmap or |
| 126 | metafile picture. All of them are defined in wxDataObject::StdFormats |
| 127 | enumeration. Of course, it's not always enough and you'll often need your |
| 128 | own format for data transfer. The simple helper class wxDataFormat may help |
| 129 | you: when you create an object of this class, it registers a new clipboard |
| 130 | data format identified by the string passed to it's ctor. |
| 131 | |
| 132 | After your new format is registered, you may use it as any other one. |
| 133 | |
| 134 | 4. Drop Source |
| 135 | ----------- |
| 136 | |
| 137 | a) Starting the d&d operation |
| 138 | |
| 139 | In order to start the d&d operation you should call the DoDragDrop function |
| 140 | (typically in reply to a "mouse button press" message). NB: DoDragDrop() is a |
| 141 | blocking function which enters into it's own message loop and may return after |
| 142 | an arbitrarily long time interval. During it, the QueryContinueDrag() is called |
| 143 | whenever the mouse or keyboard state changes. The default behaviour is quite |
| 144 | reasonable for 99% of cases: the drag operation is cancelled if the <Esc> key |
| 145 | is preessed and the drop is initiated if the mouse button is released. |
| 146 | |
| 147 | b) After the end of d&d |
| 148 | |
| 149 | The drop source behaviour depends on DoDragDrop() return code. If it |
| 150 | returns wxDropSource::None or wxDropSource::Copy there is normally nothing to |
| 151 | do, but you shouldn't forget to delete your data if it returns the |
| 152 | wxDropSource::Move code. |
| 153 | |
| 154 | c) DoDragDrop |
| 155 | |
| 156 | d) QueryContinueDrag |
| 157 | |
| 158 | |
| 159 | 5. Remarks |
| 160 | ------- |
| 161 | |
| 162 | |
| 163 | @@@@ TODO: support tymed != TYMED_HGLOBAL; |
| 164 | better support of CF_BMP, CF_METAFILE |
| 165 | scrolling support!! (how?) |
| 166 | sample demonstrating use of user-defined formats |
| 167 | sample which really does something useful |