diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2002-02-24 17:52:18 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2002-02-24 17:52:18 +0000 |
| commit | 4603756ed1284dfc9d71a556976f4f5b898abd24 (patch) | |
| tree | 4a6305d9017b0dc0c34ae97b3ed44f3266a1c1be /src | |
| parent | 0372675ee12e54acd993f6d25a9489c1373caf75 (diff) | |
- added Win32 native drag'n'drop code
- added dnd support for Fl_Group (not tested with X!)
- added dnd support for Fl_Input (not tested with X!)
- no Mac implementation yet!
Go ahead: drag text or a file from the explorer into
a text widget! Tadaa!
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1971 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl.cxx | 31 | ||||
| -rw-r--r-- | src/Fl_Group.cxx | 42 | ||||
| -rw-r--r-- | src/Fl_Input.cxx | 84 | ||||
| -rw-r--r-- | src/Fl_cutpaste_win32.cxx | 28 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 13 | ||||
| -rw-r--r-- | src/fl_dnd.cxx | 8 | ||||
| -rw-r--r-- | src/fl_dnd_win32.cxx | 329 |
7 files changed, 480 insertions, 55 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx index d3f10af9c..f7aa5b027 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl.cxx,v 1.24.2.41.2.19 2002/02/20 19:29:57 easysw Exp $" +// "$Id: Fl.cxx,v 1.24.2.41.2.20 2002/02/24 17:52:17 matthiaswm Exp $" // // Main event handling code for the Fast Light Tool Kit (FLTK). // @@ -416,13 +416,17 @@ void Fl::focus(Fl_Widget *o) { } } +static char dnd_flag = 0; // make 'belowmouse' send DND_LEAVE instead of LEAVE + void Fl::belowmouse(Fl_Widget *o) { if (grab()) return; // don't do anything while grab is on Fl_Widget *p = belowmouse_; if (o != p) { - Fl_Tooltip::enter(o); + if (!dnd_flag) Fl_Tooltip::enter(o); belowmouse_ = o; - for (; p && !p->contains(o); p = p->parent()) p->handle(FL_LEAVE); + for (; p && !p->contains(o); p = p->parent()) { + p->handle(dnd_flag ? FL_DND_LEAVE : FL_LEAVE); + } } } @@ -555,6 +559,21 @@ int Fl::handle(int event, Fl_Window* window) window->show(); return 1; + case FL_DND_ENTER: + case FL_DND_DRAG: + dnd_flag = 1; + break; + + case FL_DND_LEAVE: + dnd_flag = 1; + belowmouse(0); + dnd_flag = 0; + return true; + + case FL_DND_RELEASE: + w = belowmouse(); + break; + case FL_MOVE: case FL_DRAG: fl_xmousewin = window; // this should already be set, but just in case. @@ -643,7 +662,9 @@ int Fl::handle(int event, Fl_Window* window) break; } if (w && send(event, w, window)) return 1; - return send_handlers(event); + int ret = send_handlers(event); + dnd_flag = 0; + return ret; } //////////////////////////////////////////////////////////////// @@ -855,5 +876,5 @@ void Fl_Window::flush() { } // -// End of "$Id: Fl.cxx,v 1.24.2.41.2.19 2002/02/20 19:29:57 easysw Exp $". +// End of "$Id: Fl.cxx,v 1.24.2.41.2.20 2002/02/24 17:52:17 matthiaswm Exp $". // diff --git a/src/Fl_Group.cxx b/src/Fl_Group.cxx index c4846f573..85d4273ae 100644 --- a/src/Fl_Group.cxx +++ b/src/Fl_Group.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_Group.cxx,v 1.8.2.8.2.10 2002/02/13 03:55:10 easysw Exp $" +// "$Id: Fl_Group.cxx,v 1.8.2.8.2.11 2002/02/24 17:52:17 matthiaswm Exp $" // // Group widget for the Fast Light Tool Kit (FLTK). // @@ -56,11 +56,28 @@ extern Fl_Widget* fl_oldfocus; // set by Fl::focus static int send(Fl_Widget* o, int event) { if (o->type() < FL_WINDOW) return o->handle(event); + switch ( event ) + { + case FL_DND_ENTER: + case FL_DND_DRAG: + // figure out correct type of event: + event = (o->contains(Fl::belowmouse())) ? FL_DND_DRAG : FL_DND_ENTER; + } int save_x = Fl::e_x; Fl::e_x -= o->x(); int save_y = Fl::e_y; Fl::e_y -= o->y(); int ret = o->handle(event); Fl::e_y = save_y; Fl::e_x = save_x; + switch ( event ) + { + case FL_ENTER: + case FL_DND_ENTER: + // Successful completion of FL_ENTER means the widget is now the + // belowmouse widget, but only call Fl::belowmouse if the child + // widget did not do so: + if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o); + break; + } return ret; } @@ -156,6 +173,22 @@ int Fl_Group::handle(int event) { Fl::belowmouse(this); return 1; + case FL_DND_ENTER: + case FL_DND_DRAG: + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o)) { + if (o->contains(Fl::belowmouse())) { + return send(o,FL_DND_DRAG); + } else if (send(o,FL_DND_ENTER)) { + if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o); + return 1; + } + } + } + Fl::belowmouse(this); + return 0; + case FL_PUSH: Fl_Tooltip::exit(this); // tooltip for (i = children(); i--;) { @@ -212,8 +245,7 @@ int Fl_Group::handle(int event) { if (children()) { for (int j = i;;) { - if (child(j)->takesevents()) - if (send(child(j), event)) return 1; + if (send(child(j), event)) return 1; j++; if (j >= children()) j = 0; if (j == i) break; @@ -416,7 +448,7 @@ short* Fl_Group::sizes() { void Fl_Group::resize(int X, int Y, int W, int H) { - if (!resizable() || W==w() && H==h()) { + if (!resizable() || W==w() && H==h() ) { if (type() < FL_WINDOW) { int dx = X-x(); @@ -553,5 +585,5 @@ void Fl_Group::draw_outside_label(const Fl_Widget& w) const { } // -// End of "$Id: Fl_Group.cxx,v 1.8.2.8.2.10 2002/02/13 03:55:10 easysw Exp $". +// End of "$Id: Fl_Group.cxx,v 1.8.2.8.2.11 2002/02/24 17:52:17 matthiaswm Exp $". // diff --git a/src/Fl_Input.cxx b/src/Fl_Input.cxx index b7a322ec8..e5a57f3ef 100644 --- a/src/Fl_Input.cxx +++ b/src/Fl_Input.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_Input.cxx,v 1.10.2.15.2.5 2002/01/01 15:11:30 easysw Exp $" +// "$Id: Fl_Input.cxx,v 1.10.2.15.2.6 2002/02/24 17:52:17 matthiaswm Exp $" // // Input widget for the Fast Light Tool Kit (FLTK). // @@ -34,6 +34,8 @@ #include <FL/fl_draw.H> #include <string.h> +#define DND_OUT 1 + void Fl_Input::draw() { if (type() == FL_HIDDEN_INPUT) return; Fl_Boxtype b = box(); @@ -211,7 +213,8 @@ int Fl_Input::handle_key() { } int Fl_Input::handle(int event) { - + static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos; + static Fl_Widget *dnd_save_focus; switch (event) { case FL_FOCUS: switch (Fl::event_key()) { @@ -248,12 +251,45 @@ int Fl_Input::handle(int event) { } else return handle_key(); case FL_PUSH: +#if DND_OUT + { + int oldpos = position(), oldmark = mark(); + Fl_Boxtype b = box(); + Fl_Input_::handle_mouse( + x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b), + w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b), 0); + newpos = position(); + position( oldpos, oldmark ); + if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && type()!=FL_SECRET_INPUT && + (newpos >= mark() && newpos < position() || + newpos >= position() && newpos < mark())) { + // user clicked int the selection, may be trying to drag + drag_start = newpos; + return 1; + } + drag_start = -1; + } +#endif if (Fl::focus() != this) { Fl::focus(this); handle(FL_FOCUS); } break; + case FL_DRAG: +#if DND_OUT + if (drag_start >= 0) { + if (Fl::event_is_click()) return 1; // debounce the mouse + // save the position because sometimes we don't get DND_ENTER: + dnd_save_position = position(); + dnd_save_mark = mark(); + // drag the data: + copy(); Fl::dnd(); + return 1; + } +#endif + break; + case FL_RELEASE: if (Fl::event_button() == 2) { Fl::event_is_click(0); // stop double click from picking a word @@ -264,6 +300,48 @@ int Fl_Input::handle(int event) { } return 1; + case FL_DND_ENTER: + Fl::belowmouse(this); // send the leave events first + dnd_save_position = position(); + dnd_save_mark = mark(); + dnd_save_focus = Fl::focus(); + if (dnd_save_focus != this) { + Fl::focus(this); + handle(FL_FOCUS); + } + // fall through: + case FL_DND_DRAG: + //int p = mouse_position(X, Y, W, H); +#if DND_OUT_XXXX + if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark || + p>=dnd_save_mark && p<=dnd_save_position)) { + position(dnd_save_position, dnd_save_mark); + return 0; + } +#endif + { + Fl_Boxtype b = box(); + Fl_Input_::handle_mouse( + x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b), + w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b), 0); + } + return 1; + + case FL_DND_LEAVE: + position(dnd_save_position, dnd_save_mark); +#if DND_OUT_XXXX + if (!focused()) +#endif + if (dnd_save_focus != this) { + Fl::focus(dnd_save_focus); + handle(FL_UNFOCUS); + } + return 1; + + case FL_DND_RELEASE: + take_focus(); + return 1; + } Fl_Boxtype b = box(); return Fl_Input_::handletext(event, @@ -276,5 +354,5 @@ Fl_Input::Fl_Input(int x, int y, int w, int h, const char *l) } // -// End of "$Id: Fl_Input.cxx,v 1.10.2.15.2.5 2002/01/01 15:11:30 easysw Exp $". +// End of "$Id: Fl_Input.cxx,v 1.10.2.15.2.6 2002/02/24 17:52:17 matthiaswm Exp $". // diff --git a/src/Fl_cutpaste_win32.cxx b/src/Fl_cutpaste_win32.cxx index 16df25bb3..a751213bf 100644 --- a/src/Fl_cutpaste_win32.cxx +++ b/src/Fl_cutpaste_win32.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_cutpaste_win32.cxx,v 1.5.2.8.2.2 2002/01/01 15:11:31 easysw Exp $" +// "$Id: Fl_cutpaste_win32.cxx,v 1.5.2.8.2.3 2002/02/24 17:52:17 matthiaswm Exp $" // // WIN32 cut/paste for the Fast Light Tool Kit (FLTK). // @@ -35,8 +35,8 @@ #include <string.h> #include <stdio.h> -static char *selection_buffer; -static int selection_length; +char *fl_selection_buffer; +int fl_selection_length; static int selection_buffer_length; static char beenhere; static char ignore_destroy; @@ -59,11 +59,11 @@ static int selection_xevent_handler(int) { EmptyClipboard(); // fall through... case WM_RENDERFORMAT: { - HANDLE h = GlobalAlloc(GHND, selection_length+1); + HANDLE h = GlobalAlloc(GHND, fl_selection_length+1); if (h) { LPSTR p = (LPSTR)GlobalLock(h); - memcpy(p, selection_buffer, selection_length); - p[selection_length] = 0; + memcpy(p, fl_selection_buffer, fl_selection_length); + p[fl_selection_length] = 0; GlobalUnlock(h); SetClipboardData(CF_TEXT, h); } @@ -82,13 +82,13 @@ static int selection_xevent_handler(int) { void Fl::selection(Fl_Widget &owner, const char *stuff, int len) { if (!stuff || len<0) return; if (len+1 > selection_buffer_length) { - delete[] selection_buffer; - selection_buffer = new char[len+100]; + delete[] fl_selection_buffer; + fl_selection_buffer = new char[len+100]; selection_buffer_length = len+100; } - memcpy(selection_buffer, stuff, len); - selection_buffer[len] = 0; // needed for direct paste - selection_length = len; + memcpy(fl_selection_buffer, stuff, len); + fl_selection_buffer[len] = 0; // needed for direct paste + fl_selection_length = len; ignore_destroy = 1; if (OpenClipboard(fl_xid(Fl::first_window()))) { EmptyClipboard(); @@ -111,8 +111,8 @@ void Fl::paste(Fl_Widget &receiver) { // We already have it, do it quickly without window server. // Notice that the text is clobbered if set_selection is // called in response to FL_PASTE! - Fl::e_text = selection_buffer; - Fl::e_length = selection_length; + Fl::e_text = fl_selection_buffer; + Fl::e_length = fl_selection_length; receiver.handle(FL_PASTE); } else { if (!OpenClipboard(fl_xid(Fl::first_window()))) return; @@ -135,5 +135,5 @@ void Fl::paste(Fl_Widget &receiver) { } // -// End of "$Id: Fl_cutpaste_win32.cxx,v 1.5.2.8.2.2 2002/01/01 15:11:31 easysw Exp $". +// End of "$Id: Fl_cutpaste_win32.cxx,v 1.5.2.8.2.3 2002/02/24 17:52:17 matthiaswm Exp $". // diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 11d2644bc..f9396d367 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_win32.cxx,v 1.33.2.37.2.17 2002/02/20 19:29:57 easysw Exp $" +// "$Id: Fl_win32.cxx,v 1.33.2.37.2.18 2002/02/24 17:52:17 matthiaswm Exp $" // // WIN32-specific code for the Fast Light Tool Kit (FLTK). // @@ -45,6 +45,8 @@ #include <ctype.h> #include <winuser.h> #include <commctrl.h> +#include <ole2.h> +#include <ShellApi.h> // @@ -117,6 +119,8 @@ static fd_set fdsets[3]; #define POLLOUT 4 #define POLLERR 8 +extern class FLDropTarget flDropTarget; + static int nfds = 0; static int fd_array_size = 0; static struct FD { @@ -935,6 +939,11 @@ Fl_X* Fl_X::make(Fl_Window* w) { // other windows from the code, or we loose the capture. ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); + // register all windows for potential drag'n'drop operations + { static char oleInitialized = 0; + if (!oleInitialized) { OleInitialize(0L); oleInitialized=1; } + } + RegisterDragDrop(x->xid, (IDropTarget*)&flDropTarget); if (w->modal()) {Fl::modal_ = w; fl_fix_focus();} return x; @@ -1065,5 +1074,5 @@ void Fl_Window::make_current() { } // -// End of "$Id: Fl_win32.cxx,v 1.33.2.37.2.17 2002/02/20 19:29:57 easysw Exp $". +// End of "$Id: Fl_win32.cxx,v 1.33.2.37.2.18 2002/02/24 17:52:17 matthiaswm Exp $". // diff --git a/src/fl_dnd.cxx b/src/fl_dnd.cxx index 7f961c602..c7f8b4831 100644 --- a/src/fl_dnd.cxx +++ b/src/fl_dnd.cxx @@ -1,5 +1,5 @@ // -// "$Id: fl_dnd.cxx,v 1.3.2.1 2002/01/09 21:50:02 easysw Exp $" +// "$Id: fl_dnd.cxx,v 1.3.2.2 2002/02/24 17:52:18 matthiaswm Exp $" // // Drag & Drop code for the Fast Light Tool Kit (FLTK). // @@ -25,12 +25,12 @@ #ifdef WIN32 # include "fl_dnd_win32.cxx" -//#elif defined(__APPLE__) -//# include "fl_dnd_mac.cxx" +#elif defined(__APPLE__) +# include "fl_dnd_mac.cxx" #else # include "fl_dnd_x.cxx" #endif // -// End of "$Id: fl_dnd.cxx,v 1.3.2.1 2002/01/09 21:50:02 easysw Exp $". +// End of "$Id: fl_dnd.cxx,v 1.3.2.2 2002/02/24 17:52:18 matthiaswm Exp $". // diff --git a/src/fl_dnd_win32.cxx b/src/fl_dnd_win32.cxx index 128fb6ec8..755f1f298 100644 --- a/src/fl_dnd_win32.cxx +++ b/src/fl_dnd_win32.cxx @@ -1,5 +1,5 @@ // -// "$Id: fl_dnd_win32.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $" +// "$Id: fl_dnd_win32.cxx,v 1.5.2.2 2002/02/24 17:52:18 matthiaswm Exp $" // // Drag & Drop code for the Fast Light Tool Kit (FLTK). // @@ -22,34 +22,319 @@ // // Please report all bugs and problems to "fltk-bugs@fltk.org +// This file contains win32-specific code for fltk which is always linked +// in. Search other files for "WIN32" or filenames ending in _win32.cxx +// for other system-specific code. -// Dummy version of dnd for now, it waits until the FL_RELEASE and -// then does nothing. The real version should drag the ascii text stored -// in selection_buffer (length = selection_length) and drop it on the -// target. It should either not return until the mouse is released -// or it should cause the DRAG+RELEASE events to not be passed to the -// program somehow. I'm pretty sure this is a simple call in _WIN32: +#include <config.h> +#include <FL/Fl.H> +#include <FL/win32.H> +#include <FL/Fl_Window.H> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <time.h> +#if defined(__CYGWIN__) +#include <sys/time.h> +#include <unistd.h> +#else +#include <winsock.h> +#endif +#include <ctype.h> -#include <fltk/Fl.h> -#include <fltk/Fl_Window.h> +#include <ole2.h> +#include <ShellAPI.h> -static int grabfunc(int event) { - if (event == FL_RELEASE) Fl::pushed(0); - return false; -} +extern char *fl_selection_buffer; +extern int fl_selection_length; + +Fl_Window *fl_dnd_target_window = 0; + +/** + * subclass the IDropTarget to receive data from DnD operations + */ +class FLDropTarget : public IDropTarget +{ + DWORD m_cRefCount; + DWORD lastEffect; + int px, py; +public: + FLDropTarget() : m_cRefCount(0) { } // initialize + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { + if (IID_IUnknown==riid || IID_IDropTarget==riid) + { + *ppvObject=this; + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + if( !pDataObj ) return E_INVALIDARG; + // set e_modifiers here from grfKeyState, set e_x and e_root_x + // check if FLTK handles this drag and return if it can't (i.e. BMP drag without filename) + POINT ppt; + Fl::e_x_root = ppt.x = pt.x; + Fl::e_y_root = ppt.y = pt.y; + HWND hWnd = WindowFromPoint( ppt ); + Fl_Window *target = fl_find( hWnd ); + if (target) { + Fl::e_x = Fl::e_x_root-target->x(); + Fl::e_y = Fl::e_y_root-target->y(); + } + fl_dnd_target_window = target; + px = pt.x; py = pt.y; + // FLTK has no mechanism yet for the different drop effects, so we allow move and copy + if ( target && Fl::handle( FL_DND_ENTER, target ) ) + *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; + else + *pdwEffect = DROPEFFECT_NONE; + lastEffect = *pdwEffect; + return S_OK; + } + HRESULT STDMETHODCALLTYPE DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + if ( px==pt.x && py==pt.y ) + { + *pdwEffect = lastEffect; + return S_OK; + } + if ( !fl_dnd_target_window ) + { + *pdwEffect = lastEffect = DROPEFFECT_NONE; + return S_OK; + } + // set e_modifiers here from grfKeyState, set e_x and e_root_x + Fl::e_x_root = pt.x; + Fl::e_y_root = pt.y; + if (fl_dnd_target_window) { + Fl::e_x = Fl::e_x_root-fl_dnd_target_window->x(); + Fl::e_y = Fl::e_y_root-fl_dnd_target_window->y(); + } + // Fl_Group will change DND_DRAG into DND_ENTER and DND_LEAVE if needed + if ( Fl::handle( FL_DND_DRAG, fl_dnd_target_window ) ) + *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY|DROPEFFECT_LINK; + else + *pdwEffect = DROPEFFECT_NONE; + px = pt.x; py = pt.y; + lastEffect = *pdwEffect; + return S_OK; + } + HRESULT STDMETHODCALLTYPE DragLeave() { + if ( fl_dnd_target_window ) + { + Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); + fl_dnd_target_window = 0; + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE Drop( IDataObject *data, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { + if ( !fl_dnd_target_window ) + return S_OK; + Fl_Window *target = fl_dnd_target_window; + fl_dnd_target_window = 0; + Fl::e_x_root = pt.x; + Fl::e_y_root = pt.y; + if (target) { + Fl::e_x = Fl::e_x_root-target->x(); + Fl::e_y = Fl::e_y_root-target->y(); + } + // tell FLTK that the user released an object on this widget + if ( !Fl::handle( FL_DND_RELEASE, target ) ) + return S_OK; + + Fl_Widget *w = target; + while (w->parent()) w = w->window(); + HWND hwnd = fl_xid( (Fl_Window*)w ); + + FORMATETC fmt = { 0 }; + STGMEDIUM medium = { 0 }; + fmt.tymed = TYMED_HGLOBAL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.cfFormat = CF_TEXT; + // if it is ASCII text, send an FL_PASTE with that text + if ( data->GetData( &fmt, &medium )==S_OK ) + { + void *stuff = GlobalLock( medium.hGlobal ); + //long len = GlobalSize( medium.hGlobal ); + Fl::e_length = strlen( (char*)stuff ); // min(strlen, len) + Fl::e_text = (char*)stuff; + target->handle(FL_PASTE); // e_text will be invalid after this call + GlobalUnlock( medium.hGlobal ); + ReleaseStgMedium( &medium ); + SetForegroundWindow( hwnd ); + return S_OK; + } + fmt.tymed = TYMED_HGLOBAL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.cfFormat = CF_HDROP; + // if it is a pathname list, send an FL_PASTE with a \n seperated list of filepaths + if ( data->GetData( &fmt, &medium )==S_OK ) + { + HDROP hdrop = (HDROP)medium.hGlobal; + int i, n, nn = 0, nf = DragQueryFile( hdrop, (UINT)-1, 0, 0 ); + for ( i=0; i<nf; i++ ) nn += DragQueryFile( hdrop, i, 0, 0 ); + nn += nf; + Fl::e_length = nn-1; + char *dst = Fl::e_text = (char*)malloc(nn+1); + for ( i=0; i<nf; i++ ) { + n = DragQueryFile( hdrop, i, dst, nn ); + dst += n; + if ( i<nf-1 ) *dst++ = '\n'; + } + *dst = 0; + target->handle(FL_PASTE); + free( Fl::e_text ); + ReleaseStgMedium( &medium ); + SetForegroundWindow( hwnd ); + return S_OK; + } + return S_OK; + } +} flDropTarget; + +/** + * this class is needed to allow FLTK apps to be a DnD source + */ +class FLDropSource : public IDropSource +{ + DWORD m_cRefCount; +public: + FLDropSource() { m_cRefCount = 0; } + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { + if (IID_IUnknown==riid || IID_IDropSource==riid) + { + *ppvObject=this; + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + STDMETHODIMP GiveFeedback( ulong ) { return DRAGDROP_S_USEDEFAULTCURSORS; } + STDMETHODIMP QueryContinueDrag( BOOL esc, DWORD keyState ) { + if ( esc ) + return DRAGDROP_S_CANCEL; + if ( !(keyState & MK_LBUTTON) ) + return DRAGDROP_S_DROP; + return S_OK; + } +}; -extern int (*fl_local_grab)(int); // in Fl.cxx +/** + * this is the actual object that FLTK can drop somewhere + * - the implementation is minimal, but it should work with all decent Win32 drop targets + */ +class FLDataObject : public IDataObject +{ + DWORD m_cRefCount; +public: + FLDataObject() { m_cRefCount = 1; } + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { + if (IID_IUnknown==riid || IID_IDataObject==riid) + { + *ppvObject=this; + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + // GetData currently allows ASCII text through Global Memory only + HRESULT STDMETHODCALLTYPE GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium ) { + if ((pformatetcIn->dwAspect & DVASPECT_CONTENT) && + (pformatetcIn->tymed & TYMED_HGLOBAL) && + (pformatetcIn->cfFormat == CF_TEXT)) + { + HGLOBAL gh = GlobalAlloc( GHND, fl_selection_length+1 ); + char *pMem = (char*)GlobalLock( gh ); + memmove( pMem, fl_selection_buffer, fl_selection_length ); pMem[ fl_selection_length ] = 0; + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = gh; + pmedium->pUnkForRelease = NULL; + GlobalUnlock( gh ); + return S_OK; + } + return DV_E_FORMATETC; + } + HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pformatetc ) + { + if ((pformatetc->dwAspect & DVASPECT_CONTENT) && + (pformatetc->tymed & TYMED_HGLOBAL) && + (pformatetc->cfFormat == CF_TEXT)) + return S_OK; + return DV_E_FORMATETC; + } + // all the following methods are not really needed for a DnD object + HRESULT STDMETHODCALLTYPE GetDataHere( FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( FORMATETC *in, FORMATETC *out) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE SetData( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD dir, IEnumFORMATETC **ppenumFormatEtc) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE DAdvise( FORMATETC *pformatetc, DWORD advf, + IAdviseSink *pAdvSink, DWORD *pdwConnection) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE DUnadvise( DWORD dwConnection) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE EnumDAdvise( IEnumSTATDATA **ppenumAdvise) { return E_NOTIMPL; } +}; -int Fl::dnd() { - Fl::first_window()->cursor(FL_CURSOR_HAND); - fl_local_grab = grabfunc; - while (Fl::pushed()) Fl::wait(); - Fl::first_window()->cursor(FL_CURSOR_DEFAULT); - fl_local_grab = 0; - return true; + +/** + * drag and drop whatever is in the cut-copy-paste buffer + * - create a selection first using: + * Fl::selection(Fl_Widget &owner, const char *stuff, int len) + */ +int Fl::dnd() +{ + DWORD dropEffect; + ReleaseCapture(); + + FLDataObject *fdo = new FLDataObject; + fdo->AddRef(); + FLDropSource *fds = new FLDropSource; + fds->AddRef(); + + HRESULT ret = DoDragDrop( fdo, fds, DROPEFFECT_MOVE|DROPEFFECT_LINK|DROPEFFECT_COPY, &dropEffect ); + + fdo->Release(); + fds->Release(); + + Fl_Widget *w = Fl::pushed(); + if ( w ) + { + w->handle( FL_RELEASE ); + Fl::pushed( 0 ); + } + if ( ret==DRAGDROP_S_DROP ) return true; // or DD_S_CANCEL + return false; } // -// End of "$Id: fl_dnd_win32.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $". +// End of "$Id: fl_dnd_win32.cxx,v 1.5.2.2 2002/02/24 17:52:18 matthiaswm Exp $". // |
