![]() |
|
Drag/Drop Part 2 |
DanielH
Member #934
January 2001
![]() |
As a continuation from this thread, I been working on adding drag and drop functionality to allegro. Once again, windows only as I can only test on my personal setup. MSDN has information about the functions. There are few online examples. I found this website with a link to an all 'C' source to add drop capability to a Win32 app. An edit box is created that you can drag text from one application to the box. I even cleaned up the code to remove all extraneous functions that are not needed as a target only app. I also condensed the code into two files (main.c and dropdata.c). I also changed some function names. 1// internally defined as an IDropTarget object
2typedef struct ALLEGRO_DROP ALLEGRO_DROP;
3
4// internally defined as an IDataObject object
5typedef struct ALLEGRO_DROP_DATA ALLEGRO_DROP_DATA;
6
7// calls the original function RegisterDropWindow(HWND hWnd, IDropTarget **target)
8ALLEGRO_DROP *al_create_drop(HWND hWnd);
9
10// call the original function UnRegisterDropWindow(HWND hWnd, IDropTarget *target)
11void al_destroy_drop(ALLEGRO_DROP *drop);
12
13/*
14a callback function to verify that a specific point on the window
15can accept a drop. If not set, any point will be accepted
16*/
17void al_set_drop_validate_position_func(bool(*func)(HWND hWnd, int x, int y));
18
19/*
20a callback function to accept the dropped data. This will eventually be changed to an ALLEGRO_DROP_EVENT under allegro.
21*/
22void al_set_drop_data_func(void(*func)(ALLEGRO_DROP *drop, ALLEGRO_DROP_DATA *data));
The example app, with the changes, compiles, runs, and behaves as expected. It will accept text from a secondary source. I added this file my allegro project compiles and runs. However, the window does not accept the drop. It won't accept any of the drag/drop functions (drag_enter, drag_over, drop). Any thoughts? The example source actually loads a dialog with a simple editbox. Is it the type of window that allegro creates that won't accept drops? |
Pho75_
Member #12,377
November 2010
|
I think this could only be a very rudimentary implimentation. Not even sure this belongs as an addon, because once you get into DnD, very quickly you want all the bells and whistles of a full GUI library. But it would be great example code to donate to the community. -sorry I couldn't find the contents of ALLEGRO_DROP or ALLEGRO_DROP_DATA. ALLEGRO_DROP_DATA can be anything. why not just have a "void *data;" in your ALLEGRO_DROP struct. -since you don't know what is inside of ALLEGRO_DROP_DATA you need a generic way of asking "what am I dragging or what kind of object am I dragging?" like a "const char *drag_id_string;" or a simple "int drag_id;" in the DnD struct. -u should probably keep a copy of the original ALLEGRO_EVENT that began the drag in your DnD struct or else copy all the relavant fields so they are available to the programmer, So when processing your mouse/touch events, you can know if they are related to your current DnD operation and compare to origin (position, time, etc.) and update the screen accordingly. -you need to pass the DnD struct as a parameter in all your callback funcs, otherwise at most you can only perform 1 DnD operation at a time which would be a very severe limitation to impose. worst case: the mouse and each touchscreen finger can all be dragging something simultaneously. -usually drag-and-drop has a configurable movement threshold before kicking in, otherwise it would be too sensitive (especially on high-resolution displays) -HWND is Windows specific. It needs to be generic across all platforms. At worst, pass ALLEGRO_DISPLAY instead good luck
|
SiegeLord
Member #7,827
October 2006
![]() |
Pho75_ said: Not even sure this belongs as an addon, because once you get into DnD, very quickly you want all the bells and whistles of a full GUI library. Only if by bells and whistles you mean clipboard support Incidentally, just so this doesn't get lost, I suggest, at your convenience, to make a pull request at the github mirror (https://github.com/liballeg/allegro5). It might continue to get ignored (I'm a bit busy and this still seems like it needs some work), but at least it won't get buried in the forums. "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
DanielH
Member #934
January 2001
![]() |
Pho75_, I think you're misunderstanding what I'm trying to do. I want to drag data from one application into my application not dragging objects around my screen. And, I know it needs to be platform independent. These are generic objects and functions. Each platform will need it's own implementation of those objects. I'm working on a windows version. The callbacks are for testing at the moment. Eventually, when it gets closer to finalization, I plan on instead pushing drag/drop events into a queue. At the moment, I'm just trying to get a rudimentary text dragging example running. Here is the code I have. 1// al_drop.h
2#ifndef __al_included_allegro5_aldrop_h
3#define __al_included_allegro5_aldrop_h
4
5#include <allegro5\allegro.h>
6
7#ifdef __cplusplus
8extern "C" {
9#endif
10
11typedef struct ALLEGRO_DROP_DATA ALLEGRO_DROP_DATA;
12typedef struct ALLEGRO_DROP_TARGET ALLEGRO_DROP_TARGET;
13
14ALLEGRO_DROP_TARGET *al_create_drop_target(ALLEGRO_DISPLAY *display);
15void al_destroy_drop_target(ALLEGRO_DROP_TARGET *pDropTarget);
16
17void al_set_drop_position_function(bool(*func)(ALLEGRO_DISPLAY *display, int x, int y));
18void al_set_drop_target_function(void(*func)(ALLEGRO_DISPLAY *display, int x, int y, ALLEGRO_DROP_DATA *pDropData));
19
20#ifdef __cplusplus
21}
22#endif
23
24#endif // !__al_included_allegro5_aldrop_h
1// al_drop.c
2#define STRICT
3
4#include <stdint.h>
5#include <allegro5\allegro.h>
6#include <allegro5\allegro_windows.h>
7#include <Ole2.h>
8#include "al_drop.h"
9
10static bool(*_al_drop_validate_func)(ALLEGRO_DISPLAY *display, int x, int y) = 0;
11static void(*_al_drop_function)(ALLEGRO_DISPLAY *display, int x, int y, ALLEGRO_DROP_DATA *pDropData) = 0;
12
13typedef struct ALLEGRO_DROP_DATA
14{
15 IDataObject ido;
16 int ref_count;
17 FORMATETC *m_pFormatEtc;
18 STGMEDIUM *m_pStgMedium;
19 LONG m_nNumFormats;
20 LONG m_lRefCount;
21} ALLEGRO_DROP_DATA;
22
23typedef struct ALLEGRO_DROP_TARGET
24{
25 IDropTarget idt;
26 LONG m_lRefCount;
27 ALLEGRO_DISPLAY *m_display;
28 BOOL m_fAllowDrop;
29 ALLEGRO_DROP_DATA *m_pDataObject;
30} ALLEGRO_DROP_TARGET;
31
32typedef struct _al_drop_table_t
33{
34 BEGIN_INTERFACE
35 HRESULT(STDMETHODCALLTYPE *QueryInterface)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject);
36 ULONG(STDMETHODCALLTYPE *AddRef)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget);
37 ULONG(STDMETHODCALLTYPE *Release)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget);
38 HRESULT(STDMETHODCALLTYPE *DragEnter)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in_opt ALLEGRO_DROP_DATA *pDataObject, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);
39 HRESULT(STDMETHODCALLTYPE *DragOver)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);
40 HRESULT(STDMETHODCALLTYPE *DragLeave)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget);
41 HRESULT(STDMETHODCALLTYPE *Drop)(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in_opt ALLEGRO_DROP_DATA *pDataObject, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);
42 END_INTERFACE
43} _al_drop_table_t;
44
45
46static BOOL _al_query_data_object(ALLEGRO_DROP_DATA *pDataObject)
47{
48 FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
49
50 // does the data object support CF_TEXT using a HGLOBAL?
51 return (pDataObject->ido.lpVtbl->QueryGetData((LPDATAOBJECT)pDataObject, &fmtetc) == S_OK ? TRUE : FALSE);
52}
53
54static DWORD _al_query_drop_effect(ALLEGRO_DROP_TARGET *pDropTarget, DWORD grfKeyState, POINTL pt, DWORD dwAllowed)
55{
56 DWORD dwEffect = 0;
57
58 if (0 != _al_drop_validate_func)
59 {
60 if (!_al_drop_validate_func(pDropTarget->m_display, pt.x, pt.y))
61 {
62 return dwEffect;
63 }
64 }
65
66 // 2. work out that the drop-effect should be based on grfKeyState
67 if (grfKeyState & MK_CONTROL)
68 {
69 dwEffect = dwAllowed & DROPEFFECT_COPY;
70 }
71 else
72 {
73 if (grfKeyState & MK_SHIFT)
74 {
75 dwEffect = dwAllowed & DROPEFFECT_MOVE;
76 }
77 }
78
79 // 3. no key-modifiers were specified (or drop effect not allowed), so
80 // base the effect on those allowed by the dropsource
81 if (dwEffect == 0)
82 {
83 if ((dwAllowed & DROPEFFECT_COPY) == DROPEFFECT_COPY)
84 {
85 dwEffect = DROPEFFECT_COPY;
86 }
87
88 if ((dwAllowed & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
89 {
90 dwEffect = DROPEFFECT_MOVE;
91 }
92 }
93
94 return dwEffect;
95}
96
97static ULONG STDMETHODCALLTYPE _al_drop_target_add_reference(__RPC__in ALLEGRO_DROP_TARGET *pDropTarget)
98{
99 return InterlockedIncrement(&pDropTarget->m_lRefCount);
100}
101
102static HRESULT STDMETHODCALLTYPE _al_drop_target_query_interface(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in REFIID riid, _COM_Outptr_ void **ppvObject)
103{
104 *ppvObject = NULL;
105
106 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropTarget))
107 {
108 _al_drop_target_add_reference(pDropTarget);
109 *ppvObject = pDropTarget;
110 return S_OK;
111 }
112
113 return E_NOINTERFACE;
114}
115
116static ULONG STDMETHODCALLTYPE _al_drop_target_release(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget)
117{
118 ULONG count = InterlockedDecrement(&pDropTarget->m_lRefCount);
119
120 if (count == 0)
121 {
122 free(pDropTarget);
123 }
124
125 return count;
126}
127
128static HRESULT STDMETHODCALLTYPE _al_drop_target_drag_enter(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in_opt ALLEGRO_DROP_DATA *pDataObject, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
129{
130 pDropTarget->m_fAllowDrop = _al_query_data_object(pDataObject);
131
132 if (pDropTarget->m_fAllowDrop)
133 {
134 *pdwEffect = _al_query_drop_effect(pDropTarget, grfKeyState, pt, *pdwEffect);
135 }
136 else
137 {
138 *pdwEffect = DROPEFFECT_NONE;
139 }
140
141 return S_OK;
142}
143
144static HRESULT STDMETHODCALLTYPE _al_drop_target_drag_over(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
145{
146 if (pDropTarget->m_fAllowDrop)
147 {
148 *pdwEffect = _al_query_drop_effect(pDropTarget, grfKeyState, pt, *pdwEffect);
149 }
150 else
151 {
152 *pdwEffect = DROPEFFECT_NONE;
153 }
154
155 return S_OK;
156}
157
158static HRESULT STDMETHODCALLTYPE _al_drop_target_drag_leave(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget)
159{
160 return S_OK;
161}
162
163static HRESULT STDMETHODCALLTYPE _al_drop_target_drop(__RPC__in ALLEGRO_DROP_TARGET * pDropTarget, __RPC__in_opt ALLEGRO_DROP_DATA *pDataObject, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect)
164{
165 if (pDropTarget->m_fAllowDrop)
166 {
167 if (_al_drop_function)
168 {
169 _al_drop_function(pDropTarget->m_display, pt.x, pt.y, pDataObject);
170 }
171
172 *pdwEffect = _al_query_drop_effect(pDropTarget, grfKeyState, pt, *pdwEffect);
173 }
174 else
175 {
176 *pdwEffect = DROPEFFECT_NONE;
177 }
178
179 return S_OK;
180}
181
182static _al_drop_table_t idt_vtbl =
183{
184 _al_drop_target_query_interface,
185 _al_drop_target_add_reference,
186 _al_drop_target_release,
187 _al_drop_target_drag_enter,
188 _al_drop_target_drag_over,
189 _al_drop_target_drag_leave,
190 _al_drop_target_drop
191};
192
193ALLEGRO_DROP_TARGET *al_create_drop_target(ALLEGRO_DISPLAY *display)
194{
195 ALLEGRO_DROP_TARGET *pDropTarget = (ALLEGRO_DROP_TARGET*)malloc(sizeof(ALLEGRO_DROP_TARGET));
196
197 if (0 != pDropTarget)
198 {
199 pDropTarget->idt.lpVtbl = ((IDropTargetVtbl*)&idt_vtbl);
200 pDropTarget->m_lRefCount = 1;
201 pDropTarget->m_display = display;
202 pDropTarget->m_fAllowDrop = FALSE;
203
204 if (S_OK != CoLockObjectExternal((struct IUnknown*)pDropTarget, TRUE, FALSE) ||
205 S_OK != RegisterDragDrop(al_get_win_window_handle(display), (LPDROPTARGET)pDropTarget))
206 {
207 free(pDropTarget);
208 pDropTarget = NULL;
209 }
210 }
211
212 return pDropTarget;
213}
214
215void al_destroy_drop_target(ALLEGRO_DROP_TARGET *pDropTarget)
216{
217 if (0 != pDropTarget)
218 {
219 // remove drag+drop
220 RevokeDragDrop(al_get_win_window_handle(pDropTarget->m_display));
221
222 // remove the strong lock
223 CoLockObjectExternal((struct IUnknown*)pDropTarget, FALSE, TRUE);
224
225 // release our own reference
226 ((IDropTarget*)pDropTarget)->lpVtbl->Release((IDropTarget*)pDropTarget);
227 }
228}
229
230void al_set_drop_position_function(bool(*func)(ALLEGRO_DISPLAY *display, int x, int y))
231{
232 _al_drop_validate_func = func;
233}
234
235void al_set_drop_target_function(void(*func)(ALLEGRO_DISPLAY *display, int x, int y, ALLEGRO_DROP_DATA *pDropData))
236{
237 _al_drop_function = func;
238}
|
Trent Gamblin
Member #261
April 2000
![]() |
You have functions to create and destroy ALLEGRO_DROP_TARGET but I don't see any public functions that use those.
|
Pho75_
Member #12,377
November 2010
|
DanielH, Apologies, thanks for clarifying. Cool feature to add. |
DanielH
Member #934
January 2001
![]() |
Trent - I originally had this: void al_set_drop_position_function(bool(*func)(ALLEGRO_DROP_TARGET *pDropTarget, y, int x, int y)); void al_set_drop_target_function(void(*func)(ALLEGRO_DROP_TARGET *pDropTarget, int x, int y, ALLEGRO_DROP_DATA *pDropData)); with a separate function to retrieve the display for that target ALLEGRO_DISPLAY *al_get_display_from_drop_target(ALLEGRO_DROP_TARGET *pDropTarget); At the moment, I am simplifying the whole process until I get it working. UPDATE: I finally have a working prototype. The problem was that the drop target had to be created in the same thread that processes windows messages. The new code is set up that all you have to do is or another flag when you create a new display (ALLEGRO_ACCEPT_DROP). This will setup the display to generate drag/drop events. Default: any type any where on the screen. There are functions to change this. 1// events.h
2enum
3{
4 ...
5 ALLEGRO_EVENT_DRAG_ENTER = 48,
6 ALLEGRO_EVENT_DRAG_OVER = 49,
7 ALLEGRO_EVENT_DRAG_LEAVE = 50,
8 ALLEGRO_EVENT_DROP = 51
9}
10
11typedef struct ALLEGRO_DROP_EVENT
12{
13 _AL_EVENT_HEADER(struct ALLEGRO_DISPLAY)
14 int32_t x;
15 int32_t y;
16 int32_t data_type; // text and bitmaps.
17 struct ALLEGRO_DROP_DATA *data;
18} ALLEGRO_DROP_EVENT;
1// drop.h
2#ifndef __al_included_allegro5_drop_h
3#define __al_included_allegro5_drop_h
4
5#ifdef __cplusplus
6extern "C" {
7#endif
8
9 enum {
10 ALLEGRO_DROP_TEXT = 1 << 0,
11 ALLEGRO_DROP_BITMAP = 1 << 1,
12
13 ALLEGRO_DROP_DEFAULT = 0xffff
14 };
15
16 typedef struct ALLEGRO_DROP_DATA ALLEGRO_DROP_DATA;
17
18 // creates a corresponding allegro object (ALLEGRO_USTR,ALLEGRO_BITMAP,...)
19 AL_FUNC(void*, al_retrieve_drop_data, (ALLEGRO_DROP_DATA *pDropData));
20
21 // set/get where on the display an item can be droppped (-1 on width/height for full display)
22 AL_FUNC(void, al_set_allow_drop_coordinates, (ALLEGRO_DISPLAY *display, int x, int y, int w, int h));
23 AL_FUNC(void, al_get_allow_drop_coordinates, (ALLEGRO_DISPLAY *display, int *x, int *y, int *w, int *h));
24
25 // set/get which objects can be dropped
26 AL_FUNC(void, al_set_allow_drop_type, (ALLEGRO_DISPLAY *display, int type));
27 AL_FUNC(int, al_get_allow_drop_type, (ALLEGRO_DISPLAY *display));
28
29#ifdef __cplusplus
30}
31#endif
32
33#endif // !__al_included_allegro5_drop_h
The function, al_retrieve_drop_data, needs work. Retrieving text is easy. Converting a HBITMAP to an ALLEGRO_BITMAP is needed. |
|