Merge remote-tracking branch 'cnjinhao/develop-1.7' into cmake-dev
This commit is contained in:
@@ -20,6 +20,7 @@ matrix:
|
|||||||
- alsa-oss
|
- alsa-oss
|
||||||
- libx11-dev
|
- libx11-dev
|
||||||
- libxft-dev
|
- libxft-dev
|
||||||
|
- libxcursor-dev
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ matrix:
|
|||||||
- alsa-oss
|
- alsa-oss
|
||||||
- libx11-dev
|
- libx11-dev
|
||||||
- libxft-dev
|
- libxft-dev
|
||||||
|
- libxcursor-dev
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-precise
|
- llvm-toolchain-precise
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
<Unit filename="../../source/gui/detail/native_window_interface.cpp" />
|
<Unit filename="../../source/gui/detail/native_window_interface.cpp" />
|
||||||
<Unit filename="../../source/gui/detail/window_layout.cpp" />
|
<Unit filename="../../source/gui/detail/window_layout.cpp" />
|
||||||
<Unit filename="../../source/gui/detail/window_manager.cpp" />
|
<Unit filename="../../source/gui/detail/window_manager.cpp" />
|
||||||
|
<Unit filename="../../source/gui/dragdrop.cpp" />
|
||||||
<Unit filename="../../source/gui/dragger.cpp" />
|
<Unit filename="../../source/gui/dragger.cpp" />
|
||||||
<Unit filename="../../source/gui/drawing.cpp" />
|
<Unit filename="../../source/gui/drawing.cpp" />
|
||||||
<Unit filename="../../source/gui/effects.cpp" />
|
<Unit filename="../../source/gui/effects.cpp" />
|
||||||
|
|||||||
@@ -202,6 +202,7 @@
|
|||||||
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
||||||
|
|||||||
@@ -333,6 +333,9 @@
|
|||||||
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
|
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
|
||||||
<Filter>Source Files\nana\detail</Filter>
|
<Filter>Source Files\nana\detail</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
|
||||||
|
<Filter>Source Files\nana\gui</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
|
<ClCompile Include="..\..\source\gui\widgets\group.cpp">
|
||||||
|
|||||||
@@ -196,6 +196,7 @@
|
|||||||
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
||||||
|
|||||||
@@ -291,6 +291,9 @@
|
|||||||
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
|
<ClCompile Include="..\..\source\detail\platform_abstraction.cpp">
|
||||||
<Filter>Source Files\detail</Filter>
|
<Filter>Source Files\detail</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
|
||||||
|
<Filter>Source Files\gui</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\include\nana\any.hpp">
|
<ClInclude Include="..\..\include\nana\any.hpp">
|
||||||
|
|||||||
@@ -179,6 +179,7 @@
|
|||||||
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\native_window_interface.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_layout.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
<ClCompile Include="..\..\source\gui\detail\window_manager.cpp" />
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
<ClCompile Include="..\..\source\gui\dragger.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
<ClCompile Include="..\..\source\gui\drawing.cpp" />
|
||||||
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
<ClCompile Include="..\..\source\gui\effects.cpp" />
|
||||||
|
|||||||
@@ -292,6 +292,9 @@
|
|||||||
<ClCompile Include="..\..\source\gui\wvl.cpp">
|
<ClCompile Include="..\..\source\gui\wvl.cpp">
|
||||||
<Filter>Sources\gui</Filter>
|
<Filter>Sources\gui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\source\gui\dragdrop.cpp">
|
||||||
|
<Filter>Sources\gui</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\include\nana\gui\widgets\spinbox.hpp">
|
<ClInclude Include="..\..\include\nana\gui\widgets\spinbox.hpp">
|
||||||
|
|||||||
@@ -65,6 +65,13 @@ namespace nana
|
|||||||
blend
|
blend
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class dragdrop_status
|
||||||
|
{
|
||||||
|
not_ready,
|
||||||
|
ready,
|
||||||
|
in_progress
|
||||||
|
};
|
||||||
|
|
||||||
namespace category
|
namespace category
|
||||||
{
|
{
|
||||||
enum class flags
|
enum class flags
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* A Basic Window Widget Definition
|
* A Basic Window Widget Definition
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* Nana C++ Library(http://www.nanapro.org)
|
||||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||||
*
|
*
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -179,7 +179,8 @@ namespace detail
|
|||||||
bool ignore_menubar_focus : 1; ///< A flag indicates whether the menubar sets the focus.
|
bool ignore_menubar_focus : 1; ///< A flag indicates whether the menubar sets the focus.
|
||||||
bool ignore_mouse_focus : 1; ///< A flag indicates whether the widget accepts focus when clicking on it
|
bool ignore_mouse_focus : 1; ///< A flag indicates whether the widget accepts focus when clicking on it
|
||||||
bool space_click_enabled : 1; ///< A flag indicates whether enable mouse_down/click/mouse_up when pressing and releasing whitespace key.
|
bool space_click_enabled : 1; ///< A flag indicates whether enable mouse_down/click/mouse_up when pressing and releasing whitespace key.
|
||||||
unsigned Reserved :18;
|
bool draggable : 1;
|
||||||
|
unsigned Reserved :17;
|
||||||
unsigned char tab; ///< indicate a window that can receive the keyboard TAB
|
unsigned char tab; ///< indicate a window that can receive the keyboard TAB
|
||||||
mouse_action action;
|
mouse_action action;
|
||||||
mouse_action action_before;
|
mouse_action action_before;
|
||||||
@@ -234,6 +235,7 @@ namespace detail
|
|||||||
///< if the active_window is null, the parent of this window keeps focus.
|
///< if the active_window is null, the parent of this window keeps focus.
|
||||||
paint::graphics glass_buffer; ///< if effect.bground is avaiable. Refer to window_layout::make_bground.
|
paint::graphics glass_buffer; ///< if effect.bground is avaiable. Refer to window_layout::make_bground.
|
||||||
update_state upd_state;
|
update_state upd_state;
|
||||||
|
dragdrop_status dnd_state{ dragdrop_status::not_ready };
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
|||||||
45
include/nana/gui/dragdrop.hpp
Normal file
45
include/nana/gui/dragdrop.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Drag and Drop Implementation
|
||||||
|
* Nana C++ Library(http://www.nanapro.org)
|
||||||
|
* Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com)
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* @file: nana/gui/dragdrop.hpp
|
||||||
|
* @author: Jinhao(cnjinhao@hotmail.com)
|
||||||
|
*/
|
||||||
|
#ifndef NANA_GUI_DRAGDROP_INCLUDED
|
||||||
|
#define NANA_GUI_DRAGDROP_INCLUDED
|
||||||
|
|
||||||
|
#include <nana/push_ignore_diagnostic>
|
||||||
|
#include <functional>
|
||||||
|
#include "basis.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace nana
|
||||||
|
{
|
||||||
|
class simple_dragdrop
|
||||||
|
{
|
||||||
|
struct implementation;
|
||||||
|
|
||||||
|
simple_dragdrop(const simple_dragdrop&) = delete;
|
||||||
|
simple_dragdrop& operator=(const simple_dragdrop&) = delete;
|
||||||
|
|
||||||
|
simple_dragdrop(simple_dragdrop&&) = delete;
|
||||||
|
simple_dragdrop& operator=(simple_dragdrop&&) = delete;
|
||||||
|
public:
|
||||||
|
simple_dragdrop(window drag_wd);
|
||||||
|
~simple_dragdrop();
|
||||||
|
|
||||||
|
/// Sets a condition that determines whether the drag&drop can start
|
||||||
|
void condition(std::function<bool()> predicate_fn);
|
||||||
|
void make_drop(window target, std::function<void()> drop_fn);
|
||||||
|
private:
|
||||||
|
implementation* const impl_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Nana GUI Programming Interface Implementation
|
* Nana GUI Programming Interface Implementation
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* Nana C++ Library(http://www.nanapro.org)
|
||||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||||
*
|
*
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -117,6 +117,9 @@ namespace API
|
|||||||
void lazy_refresh();
|
void lazy_refresh();
|
||||||
|
|
||||||
void draw_shortkey_underline(paint::graphics&, const std::string& text, wchar_t shortkey, std::size_t shortkey_position, const point& text_pos, const color&);
|
void draw_shortkey_underline(paint::graphics&, const std::string& text, wchar_t shortkey, std::size_t shortkey_position, const point& text_pos, const color&);
|
||||||
|
|
||||||
|
void window_draggable(window, bool enabled);
|
||||||
|
bool window_draggable(window);
|
||||||
}//end namespace dev
|
}//end namespace dev
|
||||||
|
|
||||||
|
|
||||||
@@ -476,6 +479,8 @@ namespace API
|
|||||||
::std::optional<std::pair<::nana::size, ::nana::size>> content_extent(window wd, unsigned limited_px, bool limit_width);
|
::std::optional<std::pair<::nana::size, ::nana::size>> content_extent(window wd, unsigned limited_px, bool limit_width);
|
||||||
|
|
||||||
unsigned screen_dpi(bool x_requested);
|
unsigned screen_dpi(bool x_requested);
|
||||||
|
|
||||||
|
dragdrop_status window_dragdrop_status(::nana::window);
|
||||||
}//end namespace API
|
}//end namespace API
|
||||||
|
|
||||||
}//end namespace nana
|
}//end namespace nana
|
||||||
|
|||||||
@@ -1497,6 +1497,9 @@ the nana::detail::basic_window member pointer scheme
|
|||||||
void erase(index_pairs indexes); ///<Erases specified items.
|
void erase(index_pairs indexes); ///<Erases specified items.
|
||||||
item_proxy erase(item_proxy);
|
item_proxy erase(item_proxy);
|
||||||
|
|
||||||
|
/// Returns the item which is hovered
|
||||||
|
index_pair hovered() const;
|
||||||
|
|
||||||
bool sortable() const;
|
bool sortable() const;
|
||||||
void sortable(bool enable);
|
void sortable(bool enable);
|
||||||
|
|
||||||
|
|||||||
@@ -1041,6 +1041,12 @@ namespace detail
|
|||||||
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal));
|
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_spec::msg_dispatch(std::function<bool(const msg_packet_tag&)> msg_filter_fn)
|
||||||
|
{
|
||||||
|
msg_dispatcher_->dispatch(msg_filter_fn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size)
|
void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size)
|
||||||
{
|
{
|
||||||
if(requestor)
|
if(requestor)
|
||||||
@@ -1104,6 +1110,40 @@ namespace detail
|
|||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool platform_spec::register_dragdrop(native_window_type wd, dragdrop_interface* ddrop)
|
||||||
|
{
|
||||||
|
platform_scope_guard lock;
|
||||||
|
if(0 != xdnd_.dragdrop.count(wd))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int dndver = 4;
|
||||||
|
::XChangeProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware, XA_ATOM, sizeof(int) * 8,
|
||||||
|
PropModeReplace, reinterpret_cast<unsigned char*>(&dndver), 1);
|
||||||
|
|
||||||
|
auto & ref_drop = xdnd_.dragdrop[wd];
|
||||||
|
ref_drop.dragdrop = ddrop;
|
||||||
|
ref_drop.ref_count = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dragdrop_interface* platform_spec::remove_dragdrop(native_window_type wd)
|
||||||
|
{
|
||||||
|
platform_scope_guard lock;
|
||||||
|
auto i = xdnd_.dragdrop.find(wd);
|
||||||
|
if(i == xdnd_.dragdrop.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto ddrop = i->second;
|
||||||
|
if(ddrop.ref_count <= 1)
|
||||||
|
{
|
||||||
|
xdnd_.dragdrop.erase(i);
|
||||||
|
return ddrop.dragdrop;
|
||||||
|
}
|
||||||
|
--ddrop.ref_count;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
//_m_msg_filter
|
//_m_msg_filter
|
||||||
//@return: _m_msg_filter returns three states
|
//@return: _m_msg_filter returns three states
|
||||||
// 0 = msg_dispatcher dispatches the XEvent
|
// 0 = msg_dispatcher dispatches the XEvent
|
||||||
@@ -1163,7 +1203,7 @@ namespace detail
|
|||||||
else if(evt.xselection.property == self.atombase_.xdnd_selection)
|
else if(evt.xselection.property == self.atombase_.xdnd_selection)
|
||||||
{
|
{
|
||||||
bool accepted = false;
|
bool accepted = false;
|
||||||
msg.kind = msg.kind_mouse_drop;
|
msg.kind = msg_packet_tag::pkt_family::mouse_drop;
|
||||||
msg.u.mouse_drop.window = 0;
|
msg.u.mouse_drop.window = 0;
|
||||||
if(bytes_left > 0 && type == self.xdnd_.good_type)
|
if(bytes_left > 0 && type == self.xdnd_.good_type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ namespace detail
|
|||||||
{
|
{
|
||||||
//Make a cleanup msg packet to infor the dispatcher the window is closed.
|
//Make a cleanup msg packet to infor the dispatcher the window is closed.
|
||||||
msg_packet_tag msg;
|
msg_packet_tag msg;
|
||||||
msg.kind = msg.kind_cleanup;
|
msg.kind = msg_packet_tag::pkt_family::cleanup;
|
||||||
msg.u.packet_window = wd;
|
msg.u.packet_window = wd;
|
||||||
thr->msg_queue.push_back(msg);
|
thr->msg_queue.push_back(msg);
|
||||||
}
|
}
|
||||||
@@ -171,6 +171,30 @@ namespace detail
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename MsgFilter>
|
||||||
|
void dispatch(MsgFilter msg_filter_fn)
|
||||||
|
{
|
||||||
|
auto tid = nana::system::this_thread_id();
|
||||||
|
msg_packet_tag msg;
|
||||||
|
int qstate;
|
||||||
|
|
||||||
|
//Test whether the thread is registered for window, and retrieve the queue state for event
|
||||||
|
while((qstate = _m_read_queue(tid, msg, 0)))
|
||||||
|
{
|
||||||
|
//the queue is empty
|
||||||
|
if(-1 == qstate)
|
||||||
|
{
|
||||||
|
if(false == _m_wait_for_queue(tid))
|
||||||
|
proc_.timer_proc(tid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(msg_filter_fn(msg))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void _m_msg_driver()
|
void _m_msg_driver()
|
||||||
{
|
{
|
||||||
@@ -220,7 +244,7 @@ namespace detail
|
|||||||
switch(proc_.filter_proc(event, msg_pack))
|
switch(proc_.filter_proc(event, msg_pack))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
msg_pack.kind = msg_pack.kind_xevent;
|
msg_pack.kind = msg_packet_tag::pkt_family::xevent;
|
||||||
msg_pack.u.xevent = event;
|
msg_pack.u.xevent = event;
|
||||||
_m_msg_dispatch(msg_pack);
|
_m_msg_dispatch(msg_pack);
|
||||||
break;
|
break;
|
||||||
@@ -246,9 +270,9 @@ namespace detail
|
|||||||
{
|
{
|
||||||
switch(pack.kind)
|
switch(pack.kind)
|
||||||
{
|
{
|
||||||
case msg_packet_tag::kind_xevent:
|
case msg_packet_tag::pkt_family::xevent:
|
||||||
return _m_event_window(pack.u.xevent);
|
return _m_event_window(pack.u.xevent);
|
||||||
case msg_packet_tag::kind_mouse_drop:
|
case msg_packet_tag::pkt_family::mouse_drop:
|
||||||
return pack.u.mouse_drop.window;
|
return pack.u.mouse_drop.window;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -294,7 +318,7 @@ namespace detail
|
|||||||
//Check whether the event dispatcher is used for the modal window
|
//Check whether the event dispatcher is used for the modal window
|
||||||
//and when the modal window is closing, the event dispatcher would
|
//and when the modal window is closing, the event dispatcher would
|
||||||
//stop event pumping.
|
//stop event pumping.
|
||||||
if((modal == msg.u.packet_window) && (msg.kind == msg.kind_cleanup))
|
if((modal == msg.u.packet_window) && (msg.kind == msg_packet_tag::pkt_family::cleanup))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ namespace detail
|
|||||||
{
|
{
|
||||||
struct msg_packet_tag
|
struct msg_packet_tag
|
||||||
{
|
{
|
||||||
enum kind_t{kind_xevent, kind_mouse_drop, kind_cleanup};
|
enum class pkt_family{xevent, mouse_drop, cleanup};
|
||||||
kind_t kind;
|
pkt_family kind;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
XEvent xevent;
|
XEvent xevent;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
#include "msg_packet.hpp"
|
#include "msg_packet.hpp"
|
||||||
#include "../platform_abstraction_types.hpp"
|
#include "../platform_abstraction_types.hpp"
|
||||||
|
|
||||||
@@ -176,6 +177,12 @@ namespace detail
|
|||||||
~platform_scope_guard();
|
~platform_scope_guard();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class dragdrop_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~dragdrop_interface() = default;
|
||||||
|
};
|
||||||
|
|
||||||
class platform_spec
|
class platform_spec
|
||||||
{
|
{
|
||||||
typedef platform_spec self_type;
|
typedef platform_spec self_type;
|
||||||
@@ -246,6 +253,7 @@ namespace detail
|
|||||||
void msg_insert(native_window_type);
|
void msg_insert(native_window_type);
|
||||||
void msg_set(timer_proc_type, event_proc_type);
|
void msg_set(timer_proc_type, event_proc_type);
|
||||||
void msg_dispatch(native_window_type modal);
|
void msg_dispatch(native_window_type modal);
|
||||||
|
void msg_dispatch(std::function<bool(const msg_packet_tag&)>);
|
||||||
|
|
||||||
//X Selections
|
//X Selections
|
||||||
void* request_selection(native_window_type requester, Atom type, size_t & bufsize);
|
void* request_selection(native_window_type requester, Atom type, size_t & bufsize);
|
||||||
@@ -255,6 +263,9 @@ namespace detail
|
|||||||
//@biref: The image object should be kept for a long time till the window is closed,
|
//@biref: The image object should be kept for a long time till the window is closed,
|
||||||
// the image object is release in remove() method.
|
// the image object is release in remove() method.
|
||||||
const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&);
|
const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&);
|
||||||
|
|
||||||
|
bool register_dragdrop(native_window_type, dragdrop_interface*);
|
||||||
|
dragdrop_interface* remove_dragdrop(native_window_type);
|
||||||
private:
|
private:
|
||||||
static int _m_msg_filter(XEvent&, msg_packet_tag&);
|
static int _m_msg_filter(XEvent&, msg_packet_tag&);
|
||||||
void _m_caret_routine();
|
void _m_caret_routine();
|
||||||
@@ -311,6 +322,14 @@ namespace detail
|
|||||||
int timestamp;
|
int timestamp;
|
||||||
Window wd_src;
|
Window wd_src;
|
||||||
nana::point pos;
|
nana::point pos;
|
||||||
|
|
||||||
|
struct refcount_dragdrop
|
||||||
|
{
|
||||||
|
dragdrop_interface* dragdrop{nullptr};
|
||||||
|
std::size_t ref_count{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<native_window_type, refcount_dragdrop> dragdrop;
|
||||||
}xdnd_;
|
}xdnd_;
|
||||||
|
|
||||||
msg_dispatcher * msg_dispatcher_;
|
msg_dispatcher * msg_dispatcher_;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* A Basic Window Widget Definition
|
* A Basic Window Widget Definition
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* Nana C++ Library(http://www.nanapro.org)
|
||||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||||
*
|
*
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -410,6 +410,7 @@ namespace nana
|
|||||||
flags.enabled = true;
|
flags.enabled = true;
|
||||||
flags.modal = false;
|
flags.modal = false;
|
||||||
flags.take_active = true;
|
flags.take_active = true;
|
||||||
|
flags.draggable = false;
|
||||||
flags.dropable = false;
|
flags.dropable = false;
|
||||||
flags.fullscreen = false;
|
flags.fullscreen = false;
|
||||||
flags.tab = nana::detail::tab_type::none;
|
flags.tab = nana::detail::tab_type::none;
|
||||||
|
|||||||
@@ -418,10 +418,10 @@ namespace detail
|
|||||||
{
|
{
|
||||||
switch(msg.kind)
|
switch(msg.kind)
|
||||||
{
|
{
|
||||||
case nana::detail::msg_packet_tag::kind_xevent:
|
case nana::detail::msg_packet_tag::pkt_family::xevent:
|
||||||
window_proc_for_xevent(display, msg.u.xevent);
|
window_proc_for_xevent(display, msg.u.xevent);
|
||||||
break;
|
break;
|
||||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||||
window_proc_for_packet(display, msg);
|
window_proc_for_packet(display, msg);
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
@@ -441,7 +441,7 @@ namespace detail
|
|||||||
|
|
||||||
switch(msg.kind)
|
switch(msg.kind)
|
||||||
{
|
{
|
||||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||||
msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
|
msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
|
||||||
if(msgwd)
|
if(msgwd)
|
||||||
{
|
{
|
||||||
|
|||||||
824
source/gui/dragdrop.cpp
Normal file
824
source/gui/dragdrop.cpp
Normal file
@@ -0,0 +1,824 @@
|
|||||||
|
/**
|
||||||
|
* Drag and Drop Implementation
|
||||||
|
* Nana C++ Library(http://www.nanapro.org)
|
||||||
|
* Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com)
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* @file: nana/gui/dragdrop.cpp
|
||||||
|
* @author: Jinhao(cnjinhao@hotmail.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nana/gui/dragdrop.hpp>
|
||||||
|
#include <nana/gui/programming_interface.hpp>
|
||||||
|
|
||||||
|
#include <nana/gui/detail/bedrock.hpp>
|
||||||
|
#include <nana/gui/detail/basic_window.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
# include <windows.h>
|
||||||
|
# include <oleidl.h>
|
||||||
|
# include <comdef.h>
|
||||||
|
# include <Shlobj.h>
|
||||||
|
#elif defined(NANA_X11)
|
||||||
|
# include "../detail/posix/platform_spec.hpp"
|
||||||
|
# include <nana/gui/detail/native_window_interface.hpp>
|
||||||
|
# include <X11/Xcursor/Xcursor.h>
|
||||||
|
# include <fstream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nana
|
||||||
|
{
|
||||||
|
/// drop_association
|
||||||
|
/**
|
||||||
|
* This class is used for querying whether tow windows have a connection of drag and drop
|
||||||
|
*/
|
||||||
|
class drop_association
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void add(window source, window target)
|
||||||
|
{
|
||||||
|
assoc_[source].insert(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(window wd)
|
||||||
|
{
|
||||||
|
assoc_.erase(wd);
|
||||||
|
|
||||||
|
for (auto & assoc : assoc_)
|
||||||
|
assoc.second.erase(wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has(window source, window target) const
|
||||||
|
{
|
||||||
|
auto i = assoc_.find(source);
|
||||||
|
if (i != assoc_.end())
|
||||||
|
return (0 != i->second.count(target));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::map<window, std::set<window>> assoc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
template<typename Interface, const IID& iid>
|
||||||
|
class win32com_iunknown : public Interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Implements IUnknown
|
||||||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
if (riid == IID_IUnknown || riid == iid) {
|
||||||
|
*ppv = static_cast<IUnknown*>(this);
|
||||||
|
AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
*ppv = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&ref_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
LONG cRef = InterlockedDecrement(&ref_count_);
|
||||||
|
if (cRef == 0) delete this;
|
||||||
|
return cRef;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
LONG ref_count_{ 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class win32com_drop_target : public IDropTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
win32com_drop_target(const drop_association& drop_assoc) :
|
||||||
|
drop_assoc_(drop_assoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void set_source(window wd)
|
||||||
|
{
|
||||||
|
source_window_ = wd;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
//Implements IUnknown
|
||||||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
if (riid == IID_IUnknown || riid == IID_IDropTarget) {
|
||||||
|
*ppv = static_cast<IUnknown*>(this);
|
||||||
|
AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
*ppv = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&ref_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
LONG cRef = InterlockedDecrement(&ref_count_);
|
||||||
|
if (cRef == 0) delete this;
|
||||||
|
return cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// IDropTarget
|
||||||
|
STDMETHODIMP DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
|
||||||
|
{
|
||||||
|
*pdwEffect &= DROPEFFECT_COPY;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
|
||||||
|
{
|
||||||
|
auto hovered_wd = API::find_window(point(pt.x, pt.y));
|
||||||
|
if ((hovered_wd && (hovered_wd == source_window_)) || drop_assoc_.has(source_window_, hovered_wd))
|
||||||
|
*pdwEffect &= DROPEFFECT_COPY;
|
||||||
|
else
|
||||||
|
*pdwEffect = DROPEFFECT_NONE;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP DragLeave()
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
LONG ref_count_{ 1 };
|
||||||
|
|
||||||
|
window source_window_{ nullptr };
|
||||||
|
const drop_association& drop_assoc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class drop_source : public win32com_iunknown<IDropSource, IID_IDropSource>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
drop_source(window wd) :
|
||||||
|
window_handle_(wd)
|
||||||
|
{}
|
||||||
|
|
||||||
|
window source() const
|
||||||
|
{
|
||||||
|
return window_handle_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
// IDropSource
|
||||||
|
STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override
|
||||||
|
{
|
||||||
|
if (esc_pressed)
|
||||||
|
return DRAGDROP_S_CANCEL;
|
||||||
|
|
||||||
|
//Drop the object if left button is released.
|
||||||
|
if (0 == (key_state & (MK_LBUTTON)))
|
||||||
|
return DRAGDROP_S_DROP;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP GiveFeedback(DWORD effect) override
|
||||||
|
{
|
||||||
|
return DRAGDROP_S_USEDEFAULTCURSORS;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
window const window_handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class drop_data : public win32com_iunknown<IDataObject, IID_IDataObject>
|
||||||
|
{
|
||||||
|
struct medium
|
||||||
|
{
|
||||||
|
STGMEDIUM * stgmedium;
|
||||||
|
FORMATETC * format;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override
|
||||||
|
{
|
||||||
|
if (!(request_format && pmedium))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
pmedium->hGlobal = nullptr;
|
||||||
|
|
||||||
|
for (auto & med : mediums_)
|
||||||
|
{
|
||||||
|
if ((request_format->tymed & med.format->tymed) &&
|
||||||
|
(request_format->dwAspect == med.format->dwAspect) &&
|
||||||
|
(request_format->cfFormat == med.format->cfFormat))
|
||||||
|
{
|
||||||
|
return _m_copy_medium(pmedium, med.stgmedium, med.format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DV_E_FORMATETC;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override
|
||||||
|
{
|
||||||
|
if (NULL == pformatetc)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
|
||||||
|
return DV_E_DVASPECT;
|
||||||
|
|
||||||
|
HRESULT result = DV_E_TYMED;
|
||||||
|
|
||||||
|
for(auto & med : mediums_)
|
||||||
|
{
|
||||||
|
if (med.format->tymed & pformatetc->tymed)
|
||||||
|
{
|
||||||
|
if (med.format->cfFormat == pformatetc->cfFormat)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
result = DV_E_FORMATETC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override
|
||||||
|
{
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override
|
||||||
|
{
|
||||||
|
if (!(pformatetc && pmedium))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (pformatetc->tymed != pmedium->tymed)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
medium retain;
|
||||||
|
retain.format = new FORMATETC;
|
||||||
|
retain.stgmedium = new (std::nothrow) STGMEDIUM;
|
||||||
|
if (nullptr == retain.stgmedium)
|
||||||
|
{
|
||||||
|
delete retain.format;
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(retain.format, 0, sizeof(FORMATETC));
|
||||||
|
std::memset(retain.stgmedium, 0, sizeof(STGMEDIUM));
|
||||||
|
|
||||||
|
*retain.format = *pformatetc;
|
||||||
|
|
||||||
|
_m_copy_medium(retain.stgmedium, pmedium, pformatetc);
|
||||||
|
|
||||||
|
if (TRUE == fRelease)
|
||||||
|
::ReleaseStgMedium(pmedium);
|
||||||
|
|
||||||
|
mediums_.emplace_back(retain);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override
|
||||||
|
{
|
||||||
|
if (NULL == ppenumFormatEtc)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (DATADIR_GET != dwDirection)
|
||||||
|
return E_NOTIMPL;
|
||||||
|
|
||||||
|
*ppenumFormatEtc = NULL;
|
||||||
|
|
||||||
|
FORMATETC rgfmtetc[] =
|
||||||
|
{
|
||||||
|
{ CF_UNICODETEXT, NULL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL },
|
||||||
|
};
|
||||||
|
return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override
|
||||||
|
{
|
||||||
|
return OLE_E_ADVISENOTSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP DUnadvise(DWORD dwConnection) override
|
||||||
|
{
|
||||||
|
return OLE_E_ADVISENOTSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override
|
||||||
|
{
|
||||||
|
return OLE_E_ADVISENOTSUPPORTED;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src)
|
||||||
|
{
|
||||||
|
if (!(stgmed_dst && stgmed_src && fmt_src))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
switch (stgmed_src->tymed)
|
||||||
|
{
|
||||||
|
case TYMED_HGLOBAL:
|
||||||
|
stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0);
|
||||||
|
break;
|
||||||
|
case TYMED_GDI:
|
||||||
|
stgmed_dst->hBitmap = (HBITMAP)OleDuplicateData(stgmed_src->hBitmap, fmt_src->cfFormat, 0);
|
||||||
|
break;
|
||||||
|
case TYMED_MFPICT:
|
||||||
|
stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0);
|
||||||
|
break;
|
||||||
|
case TYMED_ENHMF:
|
||||||
|
stgmed_dst->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(stgmed_src->hEnhMetaFile, fmt_src->cfFormat, 0);
|
||||||
|
break;
|
||||||
|
case TYMED_FILE:
|
||||||
|
stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0);
|
||||||
|
break;
|
||||||
|
case TYMED_ISTREAM:
|
||||||
|
stgmed_dst->pstm = stgmed_src->pstm;
|
||||||
|
stgmed_src->pstm->AddRef();
|
||||||
|
break;
|
||||||
|
case TYMED_ISTORAGE:
|
||||||
|
stgmed_dst->pstg = stgmed_src->pstg;
|
||||||
|
stgmed_src->pstg->AddRef();
|
||||||
|
break;
|
||||||
|
case TYMED_NULL:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stgmed_dst->tymed = stgmed_src->tymed;
|
||||||
|
stgmed_dst->pUnkForRelease = nullptr;
|
||||||
|
if (stgmed_src->pUnkForRelease)
|
||||||
|
{
|
||||||
|
stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease;
|
||||||
|
stgmed_src->pUnkForRelease->AddRef();
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector<medium> mediums_;
|
||||||
|
};
|
||||||
|
#elif defined(NANA_X11)
|
||||||
|
class x11_dragdrop: public detail::dragdrop_interface
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class shared_icons
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
shared_icons()
|
||||||
|
{
|
||||||
|
path_ = "/usr/share/icons/";
|
||||||
|
ifs_.open(path_ + "default/index.theme");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cursor(const std::string& name)
|
||||||
|
{
|
||||||
|
auto theme = _m_read("Icon Theme", "Inherits");
|
||||||
|
|
||||||
|
return path_ + theme + "/cursors/" + name;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string _m_read(const std::string& category, const std::string& key)
|
||||||
|
{
|
||||||
|
ifs_.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
bool found_cat = false;
|
||||||
|
while(ifs_.good())
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
std::getline(ifs_, text);
|
||||||
|
|
||||||
|
if(0 == text.find('['))
|
||||||
|
{
|
||||||
|
if(found_cat)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(text.find(category + "]") != text.npos)
|
||||||
|
{
|
||||||
|
found_cat = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(found_cat && (text.find(key + "=") == 0))
|
||||||
|
{
|
||||||
|
return text.substr(key.size() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string path_;
|
||||||
|
std::ifstream ifs_;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class dragdrop_service
|
||||||
|
{
|
||||||
|
dragdrop_service() = default;
|
||||||
|
public:
|
||||||
|
static dragdrop_service& instance()
|
||||||
|
{
|
||||||
|
static dragdrop_service serv;
|
||||||
|
return serv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_dragdrop(window wd)
|
||||||
|
{
|
||||||
|
auto native_wd = API::root(wd);
|
||||||
|
if (nullptr == native_wd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
if(table_.empty())
|
||||||
|
::OleInitialize(nullptr);
|
||||||
|
|
||||||
|
win32com_drop_target* drop_target = nullptr;
|
||||||
|
|
||||||
|
auto i = table_.find(native_wd);
|
||||||
|
if (i == table_.end())
|
||||||
|
{
|
||||||
|
drop_target = new win32com_drop_target{drop_assoc_};
|
||||||
|
::RegisterDragDrop(reinterpret_cast<HWND>(native_wd), drop_target);
|
||||||
|
|
||||||
|
table_[native_wd] = drop_target;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drop_target = i->second;
|
||||||
|
drop_target->AddRef();
|
||||||
|
}
|
||||||
|
#elif defined(NANA_X11)
|
||||||
|
auto ddrop = new x11_dragdrop;
|
||||||
|
if(!_m_spec().register_dragdrop(native_wd, ddrop))
|
||||||
|
delete ddrop;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(window wd)
|
||||||
|
{
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
auto i = table_.find(API::root(wd));
|
||||||
|
if (i != table_.end())
|
||||||
|
{
|
||||||
|
if (0 == i->second->Release())
|
||||||
|
table_.erase(i);
|
||||||
|
}
|
||||||
|
#elif defined(NANA_X11)
|
||||||
|
auto ddrop = _m_spec().remove_dragdrop(API::root(wd));
|
||||||
|
delete ddrop;
|
||||||
|
#endif
|
||||||
|
drop_assoc_.erase(wd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dragdrop(window drag_wd)
|
||||||
|
{
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
auto i = table_.find(API::root(drag_wd));
|
||||||
|
if (table_.end() == i)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto drop_src = new drop_source{ drag_wd };
|
||||||
|
auto drop_dat = new (std::nothrow) drop_data;
|
||||||
|
if (!drop_dat)
|
||||||
|
{
|
||||||
|
delete drop_src;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
i->second->set_source(drag_wd);
|
||||||
|
|
||||||
|
|
||||||
|
DWORD eff;
|
||||||
|
auto status = ::DoDragDrop(drop_dat, drop_src, DROPEFFECT_COPY, &eff);
|
||||||
|
|
||||||
|
i->second->set_source(nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#elif defined(NANA_X11)
|
||||||
|
auto const native_wd = reinterpret_cast<Window>(API::root(drag_wd));
|
||||||
|
|
||||||
|
{
|
||||||
|
detail::platform_scope_guard lock;
|
||||||
|
::XSetSelectionOwner(_m_spec().open_display(), _m_spec().atombase().xdnd_selection, native_wd, CurrentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hovered_.window_handle = nullptr;
|
||||||
|
hovered_.native_wd = 0;
|
||||||
|
window target_wd = 0;
|
||||||
|
auto& atombase = _m_spec().atombase();
|
||||||
|
//while(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
_m_spec().msg_dispatch([this, drag_wd, native_wd, &target_wd, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||||
|
if(detail::msg_packet_tag::pkt_family::xevent == msg_pkt.kind)
|
||||||
|
{
|
||||||
|
auto const disp = _m_spec().open_display();
|
||||||
|
if (MotionNotify == msg_pkt.u.xevent.type)
|
||||||
|
{
|
||||||
|
auto pos = API::cursor_position();
|
||||||
|
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||||
|
|
||||||
|
if(hovered_.native_wd != native_cur_wd)
|
||||||
|
{
|
||||||
|
if(hovered_.native_wd)
|
||||||
|
{
|
||||||
|
_m_free_cursor();
|
||||||
|
::XUndefineCursor(disp, hovered_.native_wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
_m_client_msg(native_cur_wd, native_wd, atombase.xdnd_enter, atombase.text_uri_list, XA_STRING);
|
||||||
|
hovered_.native_wd = native_cur_wd;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cur_wd = API::find_window(API::cursor_position());
|
||||||
|
|
||||||
|
if(hovered_.window_handle != cur_wd)
|
||||||
|
{
|
||||||
|
_m_free_cursor();
|
||||||
|
|
||||||
|
hovered_.window_handle = cur_wd;
|
||||||
|
|
||||||
|
if((drag_wd == cur_wd) || drop_assoc_.has(drag_wd, cur_wd))
|
||||||
|
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor("dnd-move").c_str());
|
||||||
|
else
|
||||||
|
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor("dnd-none").c_str());
|
||||||
|
::XDefineCursor(disp, native_cur_wd, hovered_.cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(msg_pkt.u.xevent.type == ButtonRelease)
|
||||||
|
{
|
||||||
|
target_wd = API::find_window(API::cursor_position());
|
||||||
|
::XUndefineCursor(disp, hovered_.native_wd);
|
||||||
|
_m_free_cursor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (nullptr != target_wd);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_association& drop_assoc()
|
||||||
|
{
|
||||||
|
return drop_assoc_;
|
||||||
|
}
|
||||||
|
#ifdef NANA_X11
|
||||||
|
private:
|
||||||
|
static nana::detail::platform_spec & _m_spec()
|
||||||
|
{
|
||||||
|
return nana::detail::platform_spec::instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||||
|
static void _m_client_msg(Window wd_target, Window wd_src, Atom xdnd_atom, Atom data, Atom data_type)
|
||||||
|
{
|
||||||
|
auto const display = _m_spec().open_display();
|
||||||
|
XEvent evt;
|
||||||
|
::memset(&evt, 0, sizeof evt);
|
||||||
|
evt.xany.type = ClientMessage;
|
||||||
|
evt.xany.display = display;
|
||||||
|
evt.xclient.window = wd_target;
|
||||||
|
evt.xclient.message_type = xdnd_atom;
|
||||||
|
evt.xclient.format = 32;
|
||||||
|
|
||||||
|
//Target window
|
||||||
|
evt.xclient.data.l[0] = wd_src;
|
||||||
|
//Accept set
|
||||||
|
evt.xclient.data.l[1] = 1;
|
||||||
|
evt.xclient.data.l[2] = data;
|
||||||
|
evt.xclient.data.l[3] = data_type;
|
||||||
|
evt.xclient.data.l[4] = 0;
|
||||||
|
|
||||||
|
::XSendEvent(display, wd_target, True, NoEventMask, &evt);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _m_xdnd_aware(Window wd)
|
||||||
|
{
|
||||||
|
Atom actual; int format; unsigned long count, remaining;
|
||||||
|
unsigned char *data = 0;
|
||||||
|
XGetWindowProperty(_m_spec().open_display(), wd, _m_spec().atombase().xdnd_aware,
|
||||||
|
0, 4, False, XA_ATOM, &actual, &format, &count, &remaining, &data);
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
|
if ((actual == XA_ATOM) && (format==32) && count && data)
|
||||||
|
version = int(*(Atom*)data);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
::XFree(data);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _m_free_cursor()
|
||||||
|
{
|
||||||
|
if(hovered_.cursor)
|
||||||
|
{
|
||||||
|
::XFreeCursor(_m_spec().open_display(), hovered_.cursor);
|
||||||
|
hovered_.cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
drop_association drop_assoc_;
|
||||||
|
#ifdef NANA_WINDOWS
|
||||||
|
std::map<native_window_type, win32com_drop_target*> table_;
|
||||||
|
#elif defined (NANA_X11)
|
||||||
|
shared_icons icons_;
|
||||||
|
struct hovered_status
|
||||||
|
{
|
||||||
|
Window native_wd{0};
|
||||||
|
window window_handle{nullptr};
|
||||||
|
|
||||||
|
unsigned shape{0};
|
||||||
|
Cursor cursor{0};
|
||||||
|
}hovered_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct simple_dragdrop::implementation
|
||||||
|
{
|
||||||
|
window window_handle;
|
||||||
|
std::function<bool()> predicate;
|
||||||
|
std::map<window, std::function<void()>> targets;
|
||||||
|
|
||||||
|
bool dragging{ false };
|
||||||
|
|
||||||
|
#ifdef NANA_X11
|
||||||
|
bool cancel()
|
||||||
|
{
|
||||||
|
if (!dragging)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (API::is_window(window_handle))
|
||||||
|
{
|
||||||
|
dragging = true;
|
||||||
|
using basic_window = ::nana::detail::basic_window;
|
||||||
|
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(window_handle);
|
||||||
|
real_wd->other.dnd_state = dragdrop_status::not_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
API::release_capture(window_handle);
|
||||||
|
dragging = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
simple_dragdrop::simple_dragdrop(window drag_wd) :
|
||||||
|
impl_(new implementation)
|
||||||
|
{
|
||||||
|
dragdrop_service::instance().create_dragdrop(drag_wd);
|
||||||
|
|
||||||
|
if (!API::is_window(drag_wd))
|
||||||
|
{
|
||||||
|
delete impl_;
|
||||||
|
throw std::invalid_argument("simple_dragdrop: invalid window handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_->window_handle = drag_wd;
|
||||||
|
API::dev::window_draggable(drag_wd, true);
|
||||||
|
|
||||||
|
auto & events = API::events<>(drag_wd);
|
||||||
|
|
||||||
|
#if 1 //#ifdef NANA_WINDOWS
|
||||||
|
events.mouse_down.connect_unignorable([this](const arg_mouse& arg){
|
||||||
|
if (arg.is_left_button() && API::is_window(impl_->window_handle))
|
||||||
|
{
|
||||||
|
impl_->dragging = ((!impl_->predicate) || impl_->predicate());
|
||||||
|
|
||||||
|
using basic_window = ::nana::detail::basic_window;
|
||||||
|
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(impl_->window_handle);
|
||||||
|
real_wd->other.dnd_state = dragdrop_status::ready;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#elif 1
|
||||||
|
events.mouse_down.connect_unignorable([drag_wd](const arg_mouse& arg){
|
||||||
|
if (arg.is_left_button() && API::is_window(drag_wd))
|
||||||
|
{
|
||||||
|
//API::set_capture(drag_wd, true);
|
||||||
|
|
||||||
|
using basic_window = ::nana::detail::basic_window;
|
||||||
|
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(drag_wd);
|
||||||
|
real_wd->other.dnd_state = dragdrop_status::ready;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events.mouse_move.connect_unignorable([this](const arg_mouse& arg){
|
||||||
|
if (!arg.is_left_button())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (impl_->dragging)
|
||||||
|
{
|
||||||
|
auto drop_wd = API::find_window(API::cursor_position());
|
||||||
|
auto i = impl_->targets.find(drop_wd);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((!impl_->predicate) || impl_->predicate())
|
||||||
|
{
|
||||||
|
if (API::is_window(arg.window_handle))
|
||||||
|
{
|
||||||
|
impl_->dragging = true;
|
||||||
|
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;
|
||||||
|
|
||||||
|
dragdrop_service::instance().dragdrop(arg.window_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//API::release_capture(impl_->window_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
events.mouse_up.connect_unignorable([this]{
|
||||||
|
if (impl_->cancel())
|
||||||
|
{
|
||||||
|
auto drop_wd = API::find_window(API::cursor_position());
|
||||||
|
auto i = impl_->targets.find(drop_wd);
|
||||||
|
if (impl_->targets.end() == i || !i->second)
|
||||||
|
return;
|
||||||
|
|
||||||
|
i->second();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events.key_press.connect_unignorable([this]{
|
||||||
|
impl_->cancel();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_dragdrop::~simple_dragdrop()
|
||||||
|
{
|
||||||
|
dragdrop_service::instance().remove(impl_->window_handle);
|
||||||
|
API::dev::window_draggable(impl_->window_handle, false);
|
||||||
|
delete impl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_dragdrop::condition(std::function<bool()> predicate_fn)
|
||||||
|
{
|
||||||
|
impl_->predicate.swap(predicate_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_dragdrop::make_drop(window target, std::function<void()> drop_fn)
|
||||||
|
{
|
||||||
|
dragdrop_service::instance().drop_assoc().add(impl_->window_handle, target);
|
||||||
|
impl_->targets[target].swap(drop_fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -411,6 +411,26 @@ namespace API
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void window_draggable(window wd, bool enabled)
|
||||||
|
{
|
||||||
|
auto real_wd = reinterpret_cast<basic_window*>(wd);
|
||||||
|
internal_scope_guard lock;
|
||||||
|
if (restrict::wd_manager().available(real_wd))
|
||||||
|
real_wd->flags.draggable = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool window_draggable(window wd)
|
||||||
|
{
|
||||||
|
auto real_wd = reinterpret_cast<basic_window*>(wd);
|
||||||
|
internal_scope_guard lock;
|
||||||
|
if (restrict::wd_manager().available(real_wd))
|
||||||
|
return real_wd->flags.draggable;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}//end namespace dev
|
}//end namespace dev
|
||||||
|
|
||||||
widget* get_widget(window wd)
|
widget* get_widget(window wd)
|
||||||
@@ -1518,5 +1538,16 @@ namespace API
|
|||||||
{
|
{
|
||||||
return ::nana::platform_abstraction::screen_dpi(x_requested);
|
return ::nana::platform_abstraction::screen_dpi(x_requested);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dragdrop_status window_dragdrop_status(::nana::window wd)
|
||||||
|
{
|
||||||
|
auto real_wd = reinterpret_cast<basic_window*>(wd);
|
||||||
|
internal_scope_guard lock;
|
||||||
|
|
||||||
|
if (restrict::wd_manager().available(real_wd))
|
||||||
|
return real_wd->other.dnd_state;
|
||||||
|
|
||||||
|
return dragdrop_status::not_ready;
|
||||||
|
}
|
||||||
}//end namespace API
|
}//end namespace API
|
||||||
}//end namespace nana
|
}//end namespace nana
|
||||||
|
|||||||
@@ -1968,6 +1968,12 @@ namespace nana
|
|||||||
std::vector<inline_pane*> active_panes_;
|
std::vector<inline_pane*> active_panes_;
|
||||||
};//end class es_lister
|
};//end class es_lister
|
||||||
|
|
||||||
|
enum class operation_states
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
msup_deselect
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// created and live by the trigger, holds data for listbox: the state of the struct does not effect on member funcions, therefore all data members are public.
|
/// created and live by the trigger, holds data for listbox: the state of the struct does not effect on member funcions, therefore all data members are public.
|
||||||
struct essence
|
struct essence
|
||||||
@@ -1981,7 +1987,9 @@ namespace nana
|
|||||||
bool auto_draw{true};
|
bool auto_draw{true};
|
||||||
bool checkable{false};
|
bool checkable{false};
|
||||||
bool if_image{false};
|
bool if_image{false};
|
||||||
|
#if 0 //deprecated
|
||||||
bool deselect_deferred{ false }; //deselects items when mouse button is released.
|
bool deselect_deferred{ false }; //deselects items when mouse button is released.
|
||||||
|
#endif
|
||||||
unsigned text_height;
|
unsigned text_height;
|
||||||
|
|
||||||
::nana::listbox::export_options def_exp_options;
|
::nana::listbox::export_options def_exp_options;
|
||||||
@@ -1999,6 +2007,12 @@ namespace nana
|
|||||||
|
|
||||||
std::function<void(paint::graphics&, const rectangle&, bool)> ctg_icon_renderer; ///< Renderer for the category icon
|
std::function<void(paint::graphics&, const rectangle&, bool)> ctg_icon_renderer; ///< Renderer for the category icon
|
||||||
|
|
||||||
|
struct operation_rep
|
||||||
|
{
|
||||||
|
operation_states state{operation_states::none};
|
||||||
|
index_pair item;
|
||||||
|
}operation;
|
||||||
|
|
||||||
struct mouse_selection_part
|
struct mouse_selection_part
|
||||||
{
|
{
|
||||||
bool started{ false };
|
bool started{ false };
|
||||||
@@ -2121,6 +2135,10 @@ namespace nana
|
|||||||
|
|
||||||
void update_mouse_selection(const point& screen_pos)
|
void update_mouse_selection(const point& screen_pos)
|
||||||
{
|
{
|
||||||
|
//Don't update if it is not started
|
||||||
|
if (!mouse_selection.started)
|
||||||
|
return;
|
||||||
|
|
||||||
mouse_selection.screen_pos = screen_pos;
|
mouse_selection.screen_pos = screen_pos;
|
||||||
|
|
||||||
auto logic_pos = coordinate_cast(screen_pos, true);
|
auto logic_pos = coordinate_cast(screen_pos, true);
|
||||||
@@ -4132,8 +4150,13 @@ namespace nana
|
|||||||
using item_state = essence::item_state;
|
using item_state = essence::item_state;
|
||||||
using parts = essence::parts;
|
using parts = essence::parts;
|
||||||
|
|
||||||
|
#if 0 //deprecated
|
||||||
//Cancel deferred deselection operation when mouse moves.
|
//Cancel deferred deselection operation when mouse moves.
|
||||||
essence_->deselect_deferred = false;
|
essence_->deselect_deferred = false;
|
||||||
|
#else
|
||||||
|
if (operation_states::msup_deselect == essence_->operation.state)
|
||||||
|
essence_->operation.state = operation_states::none;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool need_refresh = false;
|
bool need_refresh = false;
|
||||||
|
|
||||||
@@ -4293,21 +4316,44 @@ namespace nana
|
|||||||
essence_->mouse_selection.reverse_selection = true;
|
essence_->mouse_selection.reverse_selection = true;
|
||||||
new_selected_status = !essence_->cs_status(abs_item_pos, true);
|
new_selected_status = !essence_->cs_status(abs_item_pos, true);
|
||||||
}
|
}
|
||||||
|
#if 0 //deprecated
|
||||||
|
else if (nana::mouse::right_button == arg.button)
|
||||||
|
{
|
||||||
|
//Unselects all selected items if the current item is not selected before selecting.
|
||||||
|
auto selected = lister.pick_items(true);
|
||||||
|
if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos))
|
||||||
|
lister.select_for_all(false, abs_item_pos);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (nana::mouse::right_button == arg.button)
|
//Unselects all selected items except current item if right button clicked.
|
||||||
|
lister.select_for_all(false, abs_item_pos); //cancel all selections
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto selected = lister.pick_items(true);
|
||||||
|
if (selected.cend() != std::find(selected.cbegin(), selected.cend(), item_pos))
|
||||||
{
|
{
|
||||||
//Unselects all selected items if the current item is not selected before selecting.
|
//If the current selected one has been selected before selecting, remains the selection states for all
|
||||||
auto selected = lister.pick_items(true);
|
//selected items. But these items will be unselected when the mouse is released.
|
||||||
if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos))
|
|
||||||
lister.select_for_all(false, abs_item_pos);
|
//Other items will be unselected if multiple items are selected.
|
||||||
|
if (selected.size() > 1)
|
||||||
|
{
|
||||||
|
essence_->operation.item = abs_item_pos;
|
||||||
|
|
||||||
|
//Don't deselect the selections if the listbox is draggable.
|
||||||
|
//It should remain the selections for drag-and-drop
|
||||||
|
|
||||||
|
if (!API::dev::window_draggable(arg.window_handle))
|
||||||
|
essence_->operation.state = operation_states::msup_deselect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
lister.select_for_all(false, abs_item_pos);
|
||||||
//Unselects all selected items except current item if right button clicked.
|
|
||||||
lister.select_for_all(false, abs_item_pos); //cancel all selections
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -4377,7 +4423,15 @@ namespace nana
|
|||||||
|
|
||||||
//Deselection of all items is deferred to the mouse up event when ctrl or shift is not pressed
|
//Deselection of all items is deferred to the mouse up event when ctrl or shift is not pressed
|
||||||
//Pressing ctrl or shift is to selects other items without deselecting current selections.
|
//Pressing ctrl or shift is to selects other items without deselecting current selections.
|
||||||
|
#if 0 //deprecated
|
||||||
essence_->deselect_deferred = !(arg.ctrl || arg.shift);
|
essence_->deselect_deferred = !(arg.ctrl || arg.shift);
|
||||||
|
#else
|
||||||
|
if (!(arg.ctrl || arg.shift))
|
||||||
|
{
|
||||||
|
essence_->operation.state = operation_states::msup_deselect;
|
||||||
|
essence_->operation.item = index_pair{nana::npos, nana::npos};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if(update)
|
if(update)
|
||||||
@@ -4419,11 +4473,19 @@ namespace nana
|
|||||||
need_refresh = true;
|
need_refresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 //deprecated
|
||||||
if (essence_->deselect_deferred)
|
if (essence_->deselect_deferred)
|
||||||
{
|
{
|
||||||
essence_->deselect_deferred = false;
|
essence_->deselect_deferred = false;
|
||||||
need_refresh |= (essence_->lister.select_for_all(false));
|
need_refresh |= (essence_->lister.select_for_all(false));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (operation_states::msup_deselect == essence_->operation.state)
|
||||||
|
{
|
||||||
|
essence_->operation.state = operation_states::none;
|
||||||
|
need_refresh |= essence_->lister.select_for_all(false, essence_->operation.item);
|
||||||
|
}
|
||||||
|
|
||||||
if (need_refresh)
|
if (need_refresh)
|
||||||
{
|
{
|
||||||
@@ -5790,6 +5852,18 @@ namespace nana
|
|||||||
return item_proxy(ess);
|
return item_proxy(ess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listbox::index_pair listbox::hovered() const
|
||||||
|
{
|
||||||
|
internal_scope_guard lock;
|
||||||
|
using parts = drawerbase::listbox::essence::parts;
|
||||||
|
|
||||||
|
auto & ptr_where = _m_ess().pointer_where;
|
||||||
|
if ((ptr_where.first == parts::list || ptr_where.first == parts::checker) && ptr_where.second != npos)
|
||||||
|
return _m_ess().lister.advance(_m_ess().first_display(), static_cast<int>(ptr_where.second));
|
||||||
|
|
||||||
|
return index_pair{ npos, npos };
|
||||||
|
}
|
||||||
|
|
||||||
bool listbox::sortable() const
|
bool listbox::sortable() const
|
||||||
{
|
{
|
||||||
internal_scope_guard lock;
|
internal_scope_guard lock;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace nana {
|
|||||||
|
|
||||||
bool passive{ true }; //The passive mode determines whether to update if scrollbar changes. It updates the client window if passive is true.
|
bool passive{ true }; //The passive mode determines whether to update if scrollbar changes. It updates the client window if passive is true.
|
||||||
|
|
||||||
bool drag_started{ false };
|
bool drag_view_move{ false }; //indicates the status of the content-view if it moves origin by dragging
|
||||||
point origin;
|
point origin;
|
||||||
|
|
||||||
std::shared_ptr<cv_scroll_rep> cv_scroll;
|
std::shared_ptr<cv_scroll_rep> cv_scroll;
|
||||||
@@ -120,19 +120,22 @@ namespace nana {
|
|||||||
if (!arg.is_left_button())
|
if (!arg.is_left_button())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->drag_started = this->view.view_area().is_hit(arg.pos);
|
this->drag_view_move = this->view.view_area().is_hit(arg.pos);
|
||||||
}
|
}
|
||||||
else if (event_code::mouse_move == arg.evt_code)
|
else if (event_code::mouse_move == arg.evt_code)
|
||||||
{
|
{
|
||||||
if (this->drag_started && this->drive(arg.pos))
|
if (this->drag_view_move && (dragdrop_status::not_ready == API::window_dragdrop_status(this->window_handle)))
|
||||||
{
|
{
|
||||||
tmr.interval(16);
|
if (this->drive(arg.pos))
|
||||||
tmr.start();
|
{
|
||||||
|
tmr.interval(16);
|
||||||
|
tmr.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event_code::mouse_up == arg.evt_code)
|
else if (event_code::mouse_up == arg.evt_code)
|
||||||
{
|
{
|
||||||
this->drag_started = false;
|
this->drag_view_move = false;
|
||||||
tmr.stop();
|
tmr.stop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user