From fe01aa0fd98e86755328a12ec865cbeea111934d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 16 Nov 2018 07:41:29 +0800 Subject: [PATCH] add class dragdrop --- include/nana/gui/dragdrop.hpp | 22 ++++- source/gui/dragdrop.cpp | 153 +++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/dragdrop.hpp b/include/nana/gui/dragdrop.hpp index e68279b8..96ed24ab 100644 --- a/include/nana/gui/dragdrop.hpp +++ b/include/nana/gui/dragdrop.hpp @@ -31,7 +31,7 @@ namespace nana simple_dragdrop(simple_dragdrop&&) = delete; simple_dragdrop& operator=(simple_dragdrop&&) = delete; public: - simple_dragdrop(window drag_wd); + simple_dragdrop(window source); ~simple_dragdrop(); /// Sets a condition that determines whether the drag&drop can start @@ -40,6 +40,26 @@ namespace nana private: implementation* const impl_; }; + + class dragdrop + { + struct implementation; + + dragdrop(const dragdrop&) = delete; + dragdrop& operator=(const dragdrop&) = delete; + + dragdrop(dragdrop&&) = delete; + dragdrop& operator=(dragdrop&&) = delete; + public: + dragdrop(window source); + ~dragdrop(); + + void condition(std::function predicate_fn); + + void make_data(std::function generator); + private: + implementation* const impl_; + }; } #endif \ No newline at end of file diff --git a/source/gui/dragdrop.cpp b/source/gui/dragdrop.cpp index 4751a62a..e6d653a3 100644 --- a/source/gui/dragdrop.cpp +++ b/source/gui/dragdrop.cpp @@ -225,6 +225,36 @@ namespace nana FORMATETC * format; }; public: + ~drop_data() + { + if(hglobal_) + ::GlobalFree(hglobal_); + } + + void assign(const std::vector& files) + { + std::size_t bytes = 0; + for (auto & f : files) + bytes += (f.size() + 1) * sizeof(f.front()); + + hglobal_ = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); + + auto dropfiles = reinterpret_cast(::GlobalLock(hglobal_)); + dropfiles->pFiles = sizeof(DROPFILES); + dropfiles->fWide = true; + + auto file_buf = reinterpret_cast(dropfiles) + sizeof(DROPFILES); + + for (auto & f : files) + { + std::memcpy(file_buf, f.data(), (f.size() + 1) * sizeof(f.front())); + file_buf += f.size() + 1; + } + + ::GlobalUnlock(hglobal_); + } + public: + // Implement IDataObject STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override { if (!(request_format && pmedium)) @@ -385,8 +415,11 @@ namespace nana return S_OK; } private: + HGLOBAL hglobal_{nullptr}; std::vector mediums_; }; + + #elif defined(NANA_X11) class x11_dragdrop: public detail::x11_dragdrop_interface, public dragdrop_session { @@ -897,4 +930,122 @@ namespace nana impl_->ddrop->insert(impl_->window_handle, target); impl_->targets[target].swap(drop_fn); } -} \ No newline at end of file + + + + + + + + //This is class dragdrop + struct dragdrop::implementation + { + window source_handle; + bool dragging{ false }; + std::function predicate; + + std::function generator; + + + struct event_handlers + { + nana::event_handle destroy; + nana::event_handle mouse_move; + nana::event_handle mouse_down; + }events; + + void make_data() + { + //https://www.codeproject.com/Articles/840/How-to-Implement-Drag-and-Drop-Between-Your-Progra + + std::vector files; + files.push_back(L"D:\\universal_access"); + files.push_back(L"D:\\新建文本文档.cpp"); + + std::size_t bytes = 0; + for (auto & f : files) + bytes += (f.size() + 1) * sizeof(f.front()); + + auto data_handle = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); + + auto dropfiles = reinterpret_cast(::GlobalLock(data_handle)); + dropfiles->pFiles = sizeof(DROPFILES); + dropfiles->fWide = true; + + auto file_buf = reinterpret_cast(dropfiles) + sizeof(DROPFILES); + + for (auto & f : files) + { + std::memcpy(file_buf, f.data(), (f.size() + 1) * sizeof(f.front())); + file_buf += f.size() + 1; + } + + ::GlobalUnlock(data_handle); + + + generator(); + } + }; + + dragdrop::dragdrop(window source) : + impl_(new implementation) + { + impl_->source_handle = source; + + auto & events = API::events(source); + impl_->events.destroy = events.destroy.connect_unignorable([this](const arg_destroy&) { + dragdrop_service::instance().remove(impl_->source_handle); + API::dev::window_draggable(impl_->source_handle, false); + }); + + impl_->events.mouse_down = events.mouse_down.connect_unignorable([this](const arg_mouse& arg) { + if (arg.is_left_button() && API::is_window(impl_->source_handle)) + { + impl_->dragging = ((!impl_->predicate) || impl_->predicate()); + + using basic_window = ::nana::detail::basic_window; + auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(impl_->source_handle); + real_wd->other.dnd_state = dragdrop_status::ready; + } + }); + + impl_->events.mouse_move = events.mouse_move.connect_unignorable([this](const arg_mouse& arg) { + if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle))) + return; + + using basic_window = ::nana::detail::basic_window; + auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(arg.window_handle); + real_wd->other.dnd_state = dragdrop_status::in_progress; + + impl_->make_data(); + + auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle); + + real_wd->other.dnd_state = dragdrop_status::not_ready; + impl_->dragging = false; + + if (has_dropped) + { + auto drop_wd = API::find_window(API::cursor_position()); + //auto i = impl_->targets.find(drop_wd); + //if ((impl_->targets.end() != i) && i->second) + // i->second(); + } + }); + } + + dragdrop::~dragdrop() + { + delete impl_; + } + + void dragdrop::condition(std::function predicate_fn) + { + + } + + void dragdrop::make_data(std::function generator) + { + impl_->generator = generator; + } +}//end namespace nana \ No newline at end of file