commit
d32d308d4c
@ -46,6 +46,8 @@ before_install:
|
||||
- cd ..
|
||||
- git clone --depth=1 --branch=cmake-dev https://github.com/qPCR4vir/nana-demo.git nana-demo
|
||||
- export PATH="$HOME/bin:$PATH"
|
||||
|
||||
#- mkdir ~/bin #it seemd that a bin already exists from 20170901
|
||||
- wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true
|
||||
- chmod -R +x /tmp/tools
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@ set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source)
|
||||
set(NANA_SOURCE_SUBDIRS
|
||||
/.
|
||||
/detail
|
||||
/detail/posix
|
||||
/filesystem
|
||||
/gui
|
||||
/gui/detail
|
||||
|
||||
@ -175,7 +175,7 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions
|
||||
};
|
||||
//enum class copy_options;
|
||||
|
||||
|
||||
enum class directory_options
|
||||
{
|
||||
none,
|
||||
@ -538,13 +538,20 @@ namespace std {
|
||||
namespace filesystem {
|
||||
using namespace std::experimental::filesystem;
|
||||
|
||||
#if (defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || \
|
||||
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
|
||||
path absolute(const path& p);
|
||||
path absolute(const path& p, std::error_code& err);
|
||||
|
||||
path canonical(const path& p);
|
||||
path canonical(const path& p, std::error_code& err);
|
||||
#endif
|
||||
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
|
||||
bool exists( std::filesystem::file_status s ) noexcept;
|
||||
bool exists( const std::filesystem::path& p );
|
||||
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept;
|
||||
#endif
|
||||
}
|
||||
} // std
|
||||
|
||||
|
||||
@ -22,6 +22,14 @@
|
||||
|
||||
namespace nana
|
||||
{
|
||||
/// Drag and drop actions
|
||||
enum class dnd_action
|
||||
{
|
||||
copy, ///< Copy the data to target.
|
||||
move, ///< Move the data to target.
|
||||
link ///< Create a link from source data to target.
|
||||
};
|
||||
|
||||
class simple_dragdrop
|
||||
{
|
||||
struct implementation;
|
||||
@ -67,7 +75,12 @@ namespace nana
|
||||
data(const data&) = delete;
|
||||
data& operator=(const data&) = delete;
|
||||
public:
|
||||
data();
|
||||
/// Constructor
|
||||
/**
|
||||
* Constructs a data object used for drag and drop
|
||||
* @param requested_action Indicates how the data to be transferred.
|
||||
*/
|
||||
data(dnd_action requested_action = dnd_action::copy);
|
||||
data(data&&);
|
||||
~data();
|
||||
|
||||
@ -81,9 +94,29 @@ namespace nana
|
||||
dragdrop(window source);
|
||||
~dragdrop();
|
||||
|
||||
/// Condition of dragging
|
||||
/***
|
||||
* The preciate function is called when press mouse button on the source window, it returns true to indicate the start of dragging. If the predicate is not set, it always start to drag.
|
||||
* @param predicate_fn A predicate function to be set.
|
||||
*/
|
||||
void condition(std::function<bool()> predicate_fn);
|
||||
|
||||
/// Transferred data
|
||||
/**
|
||||
* Set a data generator. When drag begins, it is called to generate a data object for transferring.
|
||||
* @param generator It returns the data for transferring.
|
||||
*/
|
||||
void prepare_data(std::function<data()> generator);
|
||||
void drop_finished(std::function<void(bool)> finish_fn);
|
||||
|
||||
/// Drop handler
|
||||
/**
|
||||
* The drop handler is called when the drop operation is completed. There are 3 parameters for the handler
|
||||
* dropped Indicates whether the data is accepted by a target window.
|
||||
* executed_action Indicates the action returned by target window. Ignore if dropped is false.
|
||||
* data_transferred The data object which is generated by the generator.
|
||||
* @param finish_fn The drop handling function.
|
||||
*/
|
||||
void drop_finished(std::function<void(bool dropped, dnd_action executed_action, data& data_transferred)> finish_fn);
|
||||
private:
|
||||
implementation* const impl_;
|
||||
};
|
||||
|
||||
@ -68,8 +68,12 @@ namespace nana
|
||||
};
|
||||
|
||||
|
||||
::std::string path() const;
|
||||
::std::string file() const;
|
||||
const ::std::string& path() const;
|
||||
const ::std::string& file() const;
|
||||
#if defined(NANA_WINDOWS)
|
||||
const ::std::vector<::std::string>& files() const;
|
||||
void allow_multi_select(bool allow);
|
||||
#endif
|
||||
|
||||
/// Display the filebox dialog
|
||||
bool show() const;
|
||||
|
||||
@ -42,6 +42,13 @@ namespace nana{
|
||||
using field_reference = place::field_reference;
|
||||
constexpr static const std::size_t npos = static_cast<std::size_t>(-1);
|
||||
|
||||
enum class background_mode
|
||||
{
|
||||
none,
|
||||
transparent,
|
||||
blending
|
||||
};
|
||||
|
||||
/// The default construction
|
||||
group();
|
||||
|
||||
@ -66,7 +73,8 @@ namespace nana{
|
||||
checkbox& add_option(::std::string);
|
||||
|
||||
/// Modifies the alignment of the title
|
||||
void caption_align(align position);
|
||||
group& caption_align(align position);
|
||||
group& caption_background_mode(background_mode mode);
|
||||
|
||||
/// Enables/disables the radio mode which is single selection
|
||||
group& radio_mode(bool);
|
||||
|
||||
@ -16,7 +16,7 @@ namespace nana{ namespace paint{
|
||||
public:
|
||||
using graph_reference = nana::paint::graphics&;
|
||||
virtual ~image_impl_interface() = 0; //The destructor is defined in ../image.cpp
|
||||
virtual bool open(const std::experimental::filesystem::path& file) = 0;
|
||||
virtual bool open(const std::filesystem::path& file) = 0;
|
||||
virtual bool open(const void* data, std::size_t bytes) = 0; // reads image from memory
|
||||
virtual bool alpha_channel() const = 0;
|
||||
virtual bool empty() const = 0;
|
||||
|
||||
@ -33,7 +33,7 @@ namespace nana
|
||||
{
|
||||
friend class graphics;
|
||||
public:
|
||||
using path_type = ::std::experimental::filesystem::path;
|
||||
using path_type = ::std::filesystem::path;
|
||||
|
||||
using font_style = ::nana::detail::font_style;
|
||||
|
||||
|
||||
@ -158,7 +158,7 @@ namespace nana
|
||||
: public font_interface
|
||||
{
|
||||
public:
|
||||
using path_type = std::experimental::filesystem::path;
|
||||
using path_type = std::filesystem::path;
|
||||
|
||||
internal_font(const path_type& ttf, const std::string& font_family, double font_size, const font_style& fs, native_font_type native_font):
|
||||
ttf_(ttf),
|
||||
|
||||
@ -28,7 +28,7 @@ namespace nana
|
||||
public:
|
||||
using font = font_interface;
|
||||
|
||||
using path_type = ::std::experimental::filesystem::path;
|
||||
using path_type = ::std::filesystem::path;
|
||||
|
||||
static void initialize();
|
||||
/// Shutdown before destruction of platform_spec
|
||||
|
||||
@ -513,6 +513,8 @@ namespace detail
|
||||
atombase_.xdnd_position = ::XInternAtom(display_, "XdndPosition", False);
|
||||
atombase_.xdnd_status = ::XInternAtom(display_, "XdndStatus", False);
|
||||
atombase_.xdnd_action_copy = ::XInternAtom(display_, "XdndActionCopy", False);
|
||||
atombase_.xdnd_action_move = ::XInternAtom(display_, "XdndActionMove", False);
|
||||
atombase_.xdnd_action_link = ::XInternAtom(display_, "XdndActionLink", False);
|
||||
atombase_.xdnd_drop = ::XInternAtom(display_, "XdndDrop", False);
|
||||
atombase_.xdnd_selection = ::XInternAtom(display_, "XdndSelection", False);
|
||||
atombase_.xdnd_typelist = ::XInternAtom(display_, "XdndTypeList", False);
|
||||
|
||||
@ -159,6 +159,8 @@ namespace detail
|
||||
Atom xdnd_position;
|
||||
Atom xdnd_status;
|
||||
Atom xdnd_action_copy;
|
||||
Atom xdnd_action_move;
|
||||
Atom xdnd_action_link;
|
||||
Atom xdnd_drop;
|
||||
Atom xdnd_selection;
|
||||
Atom xdnd_typelist;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#include <nana/c++defines.hpp>
|
||||
#if defined(NANA_POSIX) && defined(NANA_X11)
|
||||
#include "theme.hpp"
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <algorithm>
|
||||
@ -83,9 +85,9 @@ namespace nana
|
||||
return values;
|
||||
}
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string find_gnome_theme_name()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
try
|
||||
{
|
||||
//Searches all the gschema override files
|
||||
@ -154,6 +156,41 @@ namespace nana
|
||||
}
|
||||
|
||||
|
||||
std::string find_kde_theme_name()
|
||||
{
|
||||
auto home = getenv("HOME");
|
||||
if(home)
|
||||
{
|
||||
fs::path kdeglobals{home};
|
||||
kdeglobals /= ".kde/share/config/kdeglobals";
|
||||
|
||||
std::error_code err;
|
||||
if(fs::exists(kdeglobals, err))
|
||||
{
|
||||
std::ifstream ifs{kdeglobals};
|
||||
return find_value(ifs, "Icons", "Theme");
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string find_theme_name()
|
||||
{
|
||||
auto name = find_kde_theme_name();
|
||||
|
||||
if(name.empty())
|
||||
{
|
||||
name = find_gnome_theme_name();
|
||||
std::cout<<"GNOME:"<<name<<std::endl;
|
||||
return find_gnome_theme_name();
|
||||
}
|
||||
|
||||
std::cout<<"KDE:"<<name<<std::endl;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
class icon_theme
|
||||
{
|
||||
public:
|
||||
@ -241,6 +278,10 @@ namespace nana
|
||||
return dir;
|
||||
}
|
||||
|
||||
//Avoid recursively traverse directory for hicolor if current theme name is hicolor
|
||||
if("hicolor" == theme_name_)
|
||||
return {};
|
||||
|
||||
return icon_theme{"hicolor"}.find(name, size_wanted);
|
||||
}
|
||||
|
||||
@ -286,7 +327,7 @@ namespace nana
|
||||
}
|
||||
|
||||
//Cache is missed.
|
||||
auto file = icon_theme{find_gnome_theme_name()}.find(name, size_wanted);
|
||||
auto file = icon_theme{find_theme_name()}.find(name, size_wanted);
|
||||
if(!file.empty())
|
||||
iconcache_[name].emplace_back(size_wanted, file);
|
||||
|
||||
@ -295,4 +336,5 @@ namespace nana
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -16,69 +16,26 @@
|
||||
|
||||
#include "platform_spec.hpp"
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "theme.hpp"
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define DEBUG_XDND_PROTOCOL
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
#include <iostream> //debug
|
||||
#endif
|
||||
|
||||
namespace nana{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
struct xdnd_data
|
||||
{
|
||||
Atom requested_action;
|
||||
std::vector<std::filesystem::path> files;
|
||||
};
|
||||
|
||||
@ -100,31 +57,40 @@ namespace nana{
|
||||
auto disp = spec_.open_display();
|
||||
detail::platform_scope_guard lock;
|
||||
::XSetSelectionOwner(disp, spec_.atombase().xdnd_selection, source, CurrentTime);
|
||||
std::cout<<"XSetSelectionOwner "<<source<<std::endl;
|
||||
|
||||
shared_icons icons;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"XSetSelectionOwner "<<source<<std::endl;
|
||||
#endif
|
||||
/* //deprecated
|
||||
theme icons;
|
||||
cursor_.dnd_copy = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-copy").c_str());
|
||||
cursor_.dnd_move = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-move").c_str());
|
||||
cursor_.dnd_none = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-none").c_str());
|
||||
cursor_.dnd_none = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-none").c_str());
|
||||
*/
|
||||
cursor_.dnd_copy = ::XcursorLibraryLoadCursor(disp, "dnd-copy");
|
||||
cursor_.dnd_move = ::XcursorLibraryLoadCursor(disp, "dnd-move");
|
||||
cursor_.dnd_none = ::XcursorLibraryLoadCursor(disp, "dnd-none");
|
||||
}
|
||||
|
||||
~xdnd_protocol()
|
||||
{
|
||||
auto disp = spec_.open_display();
|
||||
::XFreeCursor(disp, cursor_.dnd_copy);
|
||||
::XFreeCursor(disp, cursor_.dnd_move);
|
||||
::XFreeCursor(disp, cursor_.dnd_none);
|
||||
}
|
||||
|
||||
void mouse_move(Window wd, const nana::point& pos)
|
||||
void mouse_move(Window wd, const nana::point& pos, Atom requested_action)
|
||||
{
|
||||
if(wd != target_)
|
||||
{
|
||||
_m_xdnd_leave();
|
||||
|
||||
if(_m_xdnd_enter(wd))
|
||||
_m_xdnd_position(pos);
|
||||
_m_xdnd_position(pos, requested_action);
|
||||
}
|
||||
else
|
||||
_m_xdnd_position(pos);
|
||||
_m_xdnd_position(pos, requested_action);
|
||||
}
|
||||
|
||||
void mouse_leave()
|
||||
@ -132,9 +98,14 @@ namespace nana{
|
||||
_m_xdnd_leave();
|
||||
}
|
||||
|
||||
void mouse_release()
|
||||
bool mouse_release()
|
||||
{
|
||||
_m_xdnd_drop();
|
||||
return _m_xdnd_drop();
|
||||
}
|
||||
|
||||
Atom executed_action() const
|
||||
{
|
||||
return executed_action_;
|
||||
}
|
||||
|
||||
//Return true to exit xdnd_protocol event handler
|
||||
@ -144,16 +115,18 @@ namespace nana{
|
||||
|
||||
if(atombase.xdnd_status == xclient.message_type)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Event: XdndStatus"<<std::endl;
|
||||
|
||||
#endif
|
||||
if(xdnd_status_state::position != xstate_ && xdnd_status_state::drop != xstate_)
|
||||
return false;
|
||||
|
||||
Window target_wd = static_cast<Window>(xclient.data.l[0]);
|
||||
bool is_accepted_by_target = (xclient.data.l[1] & 1);
|
||||
|
||||
std::cout<<"XdndStatus: Accepted="<<is_accepted_by_target<<", target="<<is_accepted_by_target<<std::endl;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"XdndStatus: Accepted="<<is_accepted_by_target<<", target="<<target_wd<<std::endl;
|
||||
#endif
|
||||
if(xclient.data.l[1] & 0x2)
|
||||
{
|
||||
rectangle rct{
|
||||
@ -166,21 +139,28 @@ namespace nana{
|
||||
if(!rct.empty())
|
||||
{
|
||||
mvout_table_[target_wd] = rct;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<". rct=("<<rct.x<<","<<rct.y<<","<<rct.width<<","<<rct.height<<")";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<std::endl;
|
||||
|
||||
#endif
|
||||
_m_cursor(is_accepted_by_target);
|
||||
|
||||
|
||||
|
||||
if((!is_accepted_by_target) && (xdnd_status_state::drop == xstate_))
|
||||
{
|
||||
_m_xdnd_leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
executed_action_ = xclient.data.l[4];
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<" Assign ExecutedAction = "<<static_cast<int>(executed_action_)<<std::endl;
|
||||
#endif
|
||||
|
||||
xstate_ = xdnd_status_state::normal;
|
||||
}
|
||||
else if(atombase.xdnd_finished == xclient.message_type)
|
||||
@ -193,8 +173,9 @@ namespace nana{
|
||||
{
|
||||
if(spec_.atombase().xdnd_selection == xselectionrequest.selection)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Event SelectionRequest: XdndSelection"<<std::endl;
|
||||
|
||||
#endif
|
||||
::XEvent evt;
|
||||
evt.xselection.type = SelectionNotify;
|
||||
evt.xselection.display = xselectionrequest.display;
|
||||
@ -204,6 +185,7 @@ namespace nana{
|
||||
evt.xselection.property = 0;
|
||||
evt.xselection.time = xselectionrequest.time;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
auto property_name = ::XGetAtomName(spec_.open_display(), xselectionrequest.property); //debug
|
||||
|
||||
std::cout<<"SelectionRequest"<<std::endl;
|
||||
@ -213,11 +195,13 @@ namespace nana{
|
||||
std::cout<<" property ="<<xselectionrequest.property<<", name="<<property_name<<std::endl;
|
||||
std::cout<<" target ="<<xselectionrequest.target<<std::endl;
|
||||
::XFree(property_name);
|
||||
#endif
|
||||
|
||||
if(xselectionrequest.target == spec_.atombase().text_uri_list)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"SelectionRequest target = text_uri_list";
|
||||
|
||||
#endif
|
||||
if(data.files.size())
|
||||
{
|
||||
std::string uri_list;
|
||||
@ -227,9 +211,9 @@ namespace nana{
|
||||
uri_list += file.u8string();
|
||||
uri_list += "\r\n";
|
||||
}
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<". URIs="<<uri_list<<std::endl;
|
||||
|
||||
#endif
|
||||
::XChangeProperty (spec_.open_display(),
|
||||
xselectionrequest.requestor,
|
||||
xselectionrequest.property,
|
||||
@ -242,9 +226,10 @@ namespace nana{
|
||||
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
else
|
||||
std::cout<<"SelectionRequest target = "<<xselectionrequest.target<<std::endl;
|
||||
|
||||
#endif
|
||||
platform_scope_guard lock;
|
||||
::XSendEvent(spec_.open_display(), xselectionrequest.requestor, False, 0, &evt);
|
||||
::XFlush(spec_.open_display());
|
||||
@ -254,7 +239,6 @@ namespace nana{
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
bool _m_xdnd_enter(Window wd)
|
||||
{
|
||||
//xdnd version of the window
|
||||
@ -263,13 +247,15 @@ namespace nana{
|
||||
return false;
|
||||
|
||||
target_ = wd;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send XdndEnter, text/uri-list="<<spec_.atombase().text_uri_list<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_enter, (xdnd_ver << 24), spec_.atombase().text_uri_list, XA_STRING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _m_xdnd_position(const nana::point& pos)
|
||||
void _m_xdnd_position(const nana::point& pos, Atom requested_action)
|
||||
{
|
||||
if(xdnd_status_state::normal != xstate_)
|
||||
return;
|
||||
@ -278,12 +264,13 @@ namespace nana{
|
||||
if(i != mvout_table_.end() && i->second.is_hit(pos))
|
||||
return;
|
||||
|
||||
std::cout<<"Send: XdndPosition"<<std::endl;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndPosition, RequestedAction="<<requested_action<<", XdndActionCopy="<<spec_.atombase().xdnd_action_copy<<std::endl;
|
||||
#endif
|
||||
xstate_ = xdnd_status_state::position;
|
||||
//Send XdndPosition
|
||||
long position = (pos.x << 16 | pos.y);
|
||||
_m_client_msg(spec_.atombase().xdnd_position, 0, position, CurrentTime, spec_.atombase().xdnd_action_copy);
|
||||
_m_client_msg(spec_.atombase().xdnd_position, 0, position, CurrentTime, requested_action);
|
||||
}
|
||||
|
||||
void _m_xdnd_leave()
|
||||
@ -292,19 +279,30 @@ namespace nana{
|
||||
|
||||
if(target_)
|
||||
{
|
||||
std::cout<<"Send: XdndLeave"<<std::endl;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndLeave, reset ExecutedAction"<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_leave, 0, 0, 0);
|
||||
target_ = 0;
|
||||
executed_action_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void _m_xdnd_drop()
|
||||
bool _m_xdnd_drop()
|
||||
{
|
||||
::XUndefineCursor(spec_.open_display(), source_);
|
||||
xstate_ = xdnd_status_state::drop;
|
||||
std::cout<<"Send: XdndDrop"<<std::endl;
|
||||
_m_client_msg(spec_.atombase().xdnd_drop, 0, CurrentTime, 0);
|
||||
|
||||
if(executed_action_)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndDrop"<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_drop, 0, CurrentTime, 0);
|
||||
}
|
||||
target_ = 0;
|
||||
|
||||
return (executed_action_ != 0);
|
||||
}
|
||||
private:
|
||||
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||
@ -343,7 +341,9 @@ namespace nana{
|
||||
if ((actual == XA_ATOM) && (format==32) && count && data)
|
||||
{
|
||||
version = int(*(Atom*)data);
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Get:XdndAware version:"<<version<<std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (data)
|
||||
@ -355,39 +355,17 @@ namespace nana{
|
||||
{
|
||||
::XDefineCursor(spec_.open_display(), source_, (accepted ? cursor_.dnd_move : cursor_.dnd_none));
|
||||
}
|
||||
|
||||
#if 0 //deprecated
|
||||
//Check if window has a property
|
||||
static bool _m_has_property(Window wd, Atom atom, unsigned char** data)
|
||||
{
|
||||
Atom type = 0;
|
||||
int f;
|
||||
unsigned long n, a;
|
||||
|
||||
unsigned char * data_back = nullptr;
|
||||
if(nullptr == data)
|
||||
data = &data_back;
|
||||
|
||||
if (::XGetWindowProperty(spec_.open_display(), wd, atom, 0, 0, False, AnyPropertyType, &type, &f,&n,&a,data) == Success)
|
||||
{
|
||||
//release the *data if failed to get the property or unspecified output buffer
|
||||
if((0 == type) || data_back)
|
||||
::XFree(*data);
|
||||
|
||||
return (0 != type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
nana::detail::platform_spec& spec_;
|
||||
Window const source_;
|
||||
Window target_{ 0 };
|
||||
Window const source_;
|
||||
Window target_{ 0 };
|
||||
Atom executed_action_{ 0 };
|
||||
xdnd_status_state xstate_{xdnd_status_state::normal};
|
||||
std::map<Window, nana::rectangle> mvout_table_;
|
||||
|
||||
struct cursor_rep
|
||||
{
|
||||
Cursor dnd_copy{ 0 };
|
||||
Cursor dnd_move{ 0 };
|
||||
Cursor dnd_none{ 0 };
|
||||
}cursor_;
|
||||
|
||||
@ -116,7 +116,7 @@ namespace nana
|
||||
//Windows stores file times using the FILETIME structure, which is a 64 bit value of 100ns intervals from January 1, 1601.
|
||||
//What's worse is that this 1601 date is fairly common to see given that it's the all zeroes value, and it is far before the
|
||||
//earliest date representable with time_t.std::filesystem can't change the reality of the underlying platform.
|
||||
|
||||
|
||||
|
||||
try {
|
||||
#if NANA_USING_BOOST_FILESYSTEM
|
||||
@ -275,7 +275,7 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
return has_root_directory();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool path::is_relative() const
|
||||
{
|
||||
return !is_absolute();
|
||||
@ -310,7 +310,7 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
path path::root_name() const
|
||||
{
|
||||
@ -1123,11 +1123,12 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
} //end namespace experimental
|
||||
}//end namespace nana
|
||||
|
||||
#if (defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
|
||||
namespace std
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || \
|
||||
(defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)))
|
||||
path absolute(const path& p)
|
||||
{
|
||||
if (p.empty())
|
||||
@ -1236,9 +1237,26 @@ namespace std
|
||||
{
|
||||
return canonical(p, &err);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
|
||||
bool exists( std::filesystem::file_status s ) noexcept
|
||||
{
|
||||
return s.type() != file_type::not_found;
|
||||
}
|
||||
|
||||
bool exists( const std::filesystem::path& p )
|
||||
{
|
||||
return exists(status(p));
|
||||
}
|
||||
|
||||
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept
|
||||
{
|
||||
return exists(status(p, ec));
|
||||
}
|
||||
#endif
|
||||
}//end namespace filesystem
|
||||
}//end namespace std
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -848,12 +848,17 @@ namespace nana{
|
||||
#endif
|
||||
}
|
||||
|
||||
void native_interface::refresh_window(native_window_type wd)
|
||||
void native_interface::refresh_window(native_window_type native_wd)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
::InvalidateRect(reinterpret_cast<HWND>(wd), nullptr, true);
|
||||
auto wd = reinterpret_cast<HWND>(native_wd);
|
||||
RECT r;
|
||||
::GetClientRect(wd, &r);
|
||||
::InvalidateRect(wd, &r, FALSE);
|
||||
#elif defined(NANA_X11)
|
||||
static_cast<void>(wd); //eliminate unused parameter compiler warning.
|
||||
Display * disp = restrict::spec.open_display();
|
||||
::XClearArea(disp, reinterpret_cast<Window>(native_wd), 0, 0, 1, 1, true);
|
||||
::XFlush(disp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1110,14 +1115,10 @@ namespace nana{
|
||||
if(owner && (owner != reinterpret_cast<native_window_type>(restrict::spec.root_window())))
|
||||
{
|
||||
auto origin = window_position(owner);
|
||||
#if 0
|
||||
x += origin.x;
|
||||
y += origin.y;
|
||||
#else
|
||||
|
||||
auto owner_extents = window_frame_extents(owner);
|
||||
x += origin.x + owner_extents.left;
|
||||
y += origin.y + owner_extents.top;
|
||||
#endif
|
||||
}
|
||||
|
||||
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
|
||||
|
||||
@ -1091,6 +1091,12 @@ namespace detail
|
||||
std::lock_guard<mutex_type> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd) == false) return false;
|
||||
|
||||
if ((wd->other.category == category::flags::root) && wd->is_draw_through())
|
||||
{
|
||||
native_interface::refresh_window(wd->root);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wd->displayed())
|
||||
{
|
||||
using paint_operation = window_layer::paint_operation;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
# include <windows.h>
|
||||
@ -38,17 +39,31 @@ namespace nana
|
||||
{
|
||||
struct dragdrop_data
|
||||
{
|
||||
dnd_action requested_action;
|
||||
std::vector<std::filesystem::path> files;
|
||||
};
|
||||
|
||||
#ifdef NANA_X11
|
||||
xdnd_data to_xdnd_data(const dragdrop_data& data)
|
||||
{
|
||||
xdnd_data xdata;
|
||||
xdata.files = data.files;
|
||||
return xdata;
|
||||
}
|
||||
xdnd_data to_xdnd_data() const noexcept
|
||||
{
|
||||
auto & atombase = nana::detail::platform_spec::instance().atombase();
|
||||
xdnd_data xdata;
|
||||
xdata.requested_action = atombase.xdnd_action_copy;
|
||||
|
||||
switch(requested_action)
|
||||
{
|
||||
case dnd_action::copy:
|
||||
xdata.requested_action = atombase.xdnd_action_copy; break;
|
||||
case dnd_action::move:
|
||||
xdata.requested_action = atombase.xdnd_action_move; break;
|
||||
case dnd_action::link:
|
||||
xdata.requested_action = atombase.xdnd_action_link; break;
|
||||
}
|
||||
|
||||
xdata.files = files;
|
||||
return xdata;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -179,7 +194,7 @@ namespace nana
|
||||
win32com_drop_target(bool simple_mode):
|
||||
simple_mode_(simple_mode)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
//Implements IUnknown
|
||||
@ -279,7 +294,7 @@ namespace nana
|
||||
//Drop the object if left button is released.
|
||||
if (0 == (key_state & (MK_LBUTTON)))
|
||||
return DRAGDROP_S_DROP;
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -468,7 +483,7 @@ namespace nana
|
||||
auto entry = find(*request_format, true);
|
||||
if (entry)
|
||||
return _m_copy_medium(pmedium, &entry->medium, &entry->format);
|
||||
|
||||
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
@ -481,10 +496,10 @@ namespace nana
|
||||
{
|
||||
if (NULL == pformatetc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
|
||||
return DV_E_DVASPECT;
|
||||
|
||||
|
||||
HRESULT result = DV_E_TYMED;
|
||||
|
||||
for (auto & entry : entries_)
|
||||
@ -563,7 +578,7 @@ namespace nana
|
||||
{
|
||||
if (!(stgmed_dst && stgmed_src && fmt_src))
|
||||
return E_INVALIDARG;
|
||||
|
||||
|
||||
switch (stgmed_src->tymed)
|
||||
{
|
||||
case TYMED_HGLOBAL:
|
||||
@ -646,7 +661,7 @@ namespace nana
|
||||
{
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
|
||||
std::size_t release() override
|
||||
{
|
||||
std::size_t val = --ref_count_;
|
||||
@ -743,7 +758,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
bool dragdrop(window drag_wd, dropdata_type* dropdata)
|
||||
bool dragdrop(window drag_wd, dropdata_type* dropdata, dnd_action* executed_action)
|
||||
{
|
||||
auto i = table_.find(API::root(drag_wd));
|
||||
if ((!dropdata) && table_.end() == i)
|
||||
@ -763,12 +778,25 @@ namespace nana
|
||||
|
||||
delete drop_src;
|
||||
|
||||
if (executed_action)
|
||||
{
|
||||
switch (result_effect)
|
||||
{
|
||||
case DROPEFFECT_COPY:
|
||||
*executed_action = dnd_action::copy; break;
|
||||
case DROPEFFECT_MOVE:
|
||||
*executed_action = dnd_action::move; break;
|
||||
case DROPEFFECT_LINK:
|
||||
*executed_action = dnd_action::link; break;
|
||||
}
|
||||
}
|
||||
|
||||
return (DROPEFFECT_NONE != result_effect);
|
||||
#elif defined(NANA_X11)
|
||||
auto& atombase = _m_spec().atombase();
|
||||
|
||||
auto ddrop = dynamic_cast<dragdrop_target*>(i->second);
|
||||
|
||||
|
||||
auto const native_source = reinterpret_cast<Window>(API::root(drag_wd));
|
||||
|
||||
{
|
||||
@ -779,12 +807,14 @@ namespace nana
|
||||
|
||||
hovered_.window_handle = nullptr;
|
||||
hovered_.native_wd = 0;
|
||||
window target_wd = 0;
|
||||
|
||||
|
||||
if(executed_action)
|
||||
*executed_action = dropdata->data()->requested_action;
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
{
|
||||
|
||||
_m_spec().msg_dispatch([this, ddrop, drag_wd, native_source, &target_wd, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
_m_spec().msg_dispatch([this, ddrop, drag_wd, native_source, &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();
|
||||
@ -792,35 +822,7 @@ namespace nana
|
||||
{
|
||||
auto pos = API::cursor_position();
|
||||
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||
#if 0
|
||||
const char* icon = nullptr;
|
||||
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_source, 1, atombase.xdnd_enter, atombase.text_uri_list, XA_STRING);
|
||||
hovered_.native_wd = native_cur_wd;
|
||||
|
||||
if(!ddrop->simple_mode())
|
||||
icon = "dnd-move";
|
||||
}
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
{
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
const char* icon = nullptr;
|
||||
if(hovered_.native_wd != native_cur_wd)
|
||||
{
|
||||
@ -834,54 +836,51 @@ namespace nana
|
||||
hovered_.native_wd = native_cur_wd;
|
||||
}
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
|
||||
std::cout<<" Hovered="<<cur_wd;
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
std::cout<<" Hovered="<<cur_wd;
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
std::cout<<" ICON="<<icon;
|
||||
}
|
||||
|
||||
std::cout<<std::endl;
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
std::cout<<" ICON="<<icon;
|
||||
}
|
||||
else
|
||||
icon = "dnd-move";
|
||||
|
||||
std::cout<<std::endl;
|
||||
|
||||
if(icon)
|
||||
{
|
||||
_m_free_cursor();
|
||||
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor(icon).c_str());
|
||||
::XDefineCursor(disp, native_cur_wd, hovered_.cursor);
|
||||
}
|
||||
#endif
|
||||
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor(icon).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();
|
||||
API::release_capture(drag_wd);
|
||||
return detail::propagation_chain::exit;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return detail::propagation_chain::stop;
|
||||
});
|
||||
|
||||
//In simple mode, it always returns true. The drag and drop is determined by class simple_dragdrop
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = detail::to_xdnd_data(*dropdata->data());
|
||||
auto data = dropdata->data()->to_xdnd_data();
|
||||
|
||||
API::set_capture(drag_wd, true);
|
||||
nana::detail::xdnd_protocol xdnd_proto{native_source};
|
||||
|
||||
//Not simple mode
|
||||
_m_spec().msg_dispatch([this, ddrop, &data, drag_wd, xdnd_proto, native_source, &target_wd, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
_m_spec().msg_dispatch([this, ddrop, &data, drag_wd, &xdnd_proto, native_source, &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();
|
||||
@ -890,7 +889,7 @@ namespace nana
|
||||
auto pos = API::cursor_position();
|
||||
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||
|
||||
xdnd_proto.mouse_move(native_cur_wd, pos);
|
||||
xdnd_proto.mouse_move(native_cur_wd, pos, data.requested_action);
|
||||
}
|
||||
else if(ClientMessage == msg_pkt.u.xevent.type)
|
||||
{
|
||||
@ -909,11 +908,13 @@ namespace nana
|
||||
{
|
||||
std::cout<<"ButtonRelease"<<std::endl;
|
||||
API::release_capture(drag_wd);
|
||||
|
||||
xdnd_proto.mouse_release();
|
||||
|
||||
std::cout<<"mouse_release"<<std::endl;
|
||||
target_wd = API::find_window(API::cursor_position());
|
||||
_m_free_cursor();
|
||||
|
||||
//Exits the msg loop if xdnd_proto doesn't send the XdndDrop because of refusal of the DND
|
||||
if(!xdnd_proto.mouse_release())
|
||||
return detail::propagation_chain::exit;
|
||||
}
|
||||
|
||||
return detail::propagation_chain::stop;
|
||||
@ -921,9 +922,14 @@ namespace nana
|
||||
return detail::propagation_chain::pass;
|
||||
});
|
||||
|
||||
}
|
||||
if(xdnd_proto.executed_action() != 0)
|
||||
{
|
||||
if(executed_action)
|
||||
*executed_action = _m_from_xdnd_action(xdnd_proto.executed_action());
|
||||
|
||||
return (nullptr != target_wd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@ -935,6 +941,19 @@ namespace nana
|
||||
return nana::detail::platform_spec::instance();
|
||||
}
|
||||
|
||||
static dnd_action _m_from_xdnd_action(Atom action) noexcept
|
||||
{
|
||||
auto & atombase = _m_spec().atombase();
|
||||
if(action == atombase.xdnd_action_copy)
|
||||
return dnd_action::copy;
|
||||
else if(action == atombase.xdnd_action_move)
|
||||
return dnd_action::move;
|
||||
else if(action == atombase.xdnd_action_link)
|
||||
return dnd_action::link;
|
||||
|
||||
return dnd_action::copy;
|
||||
}
|
||||
|
||||
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||
static void _m_client_msg(Window wd_target, Window wd_src, int flag, Atom xdnd_atom, Atom data, Atom data_type)
|
||||
{
|
||||
@ -973,7 +992,7 @@ namespace nana
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
#elif defined (NANA_X11)
|
||||
nana::detail::shared_icons icons_;
|
||||
nana::detail::theme icons_;
|
||||
struct hovered_status
|
||||
{
|
||||
Window native_wd{0};
|
||||
@ -1069,7 +1088,7 @@ namespace nana
|
||||
|
||||
std::unique_ptr<dragdrop_service::dropdata_type> dropdata{new dragdrop_service::dropdata_type};
|
||||
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get());
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get(), nullptr);
|
||||
|
||||
real_wd->other.dnd_state = dragdrop_status::not_ready;
|
||||
impl_->dragging = false;
|
||||
@ -1124,7 +1143,7 @@ namespace nana
|
||||
dragdrop_session * ddrop{nullptr};
|
||||
std::function<bool()> predicate;
|
||||
std::function<data()> generator;
|
||||
std::function<void(bool)> drop_finished;
|
||||
std::function<void(bool, dnd_action, data&)> drop_finished;
|
||||
|
||||
struct event_handlers
|
||||
{
|
||||
@ -1142,31 +1161,21 @@ namespace nana
|
||||
|
||||
void make_drop()
|
||||
{
|
||||
if (!generator)
|
||||
return;
|
||||
|
||||
auto transf_data = generator();
|
||||
dragdrop_service::dropdata_type dropdata;
|
||||
dropdata.assign(*transf_data.real_data_);
|
||||
/* //deprecated
|
||||
#ifdef NANA_WINDOWS
|
||||
drop_source drop_src{ source_handle };
|
||||
DWORD result_effect = DROPEFFECT_NONE;
|
||||
auto status = ::DoDragDrop(&dropdata, &drop_src, DROPEFFECT_COPY | DROPEFFECT_MOVE, &result_effect);
|
||||
|
||||
if (DROPEFFECT_NONE == result_effect)
|
||||
{
|
||||
}
|
||||
|
||||
if (drop_finished)
|
||||
drop_finished(DROPEFFECT_NONE != result_effect);
|
||||
#else
|
||||
#endif
|
||||
*/
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(source_handle, &dropdata);
|
||||
dnd_action executed_action;
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(source_handle, &dropdata, &executed_action);
|
||||
|
||||
if(drop_finished)
|
||||
drop_finished(has_dropped);
|
||||
drop_finished(has_dropped, executed_action, transf_data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
dragdrop::dragdrop(window source) :
|
||||
impl_(new implementation(source))
|
||||
{
|
||||
@ -1228,7 +1237,7 @@ namespace nana
|
||||
}
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
|
||||
void dragdrop::condition(std::function<bool()> predicate_fn)
|
||||
{
|
||||
impl_->predicate = predicate_fn;
|
||||
@ -1239,15 +1248,16 @@ namespace nana
|
||||
impl_->generator = generator;
|
||||
}
|
||||
|
||||
void dragdrop::drop_finished(std::function<void(bool)> finish_fn)
|
||||
void dragdrop::drop_finished(std::function<void(bool, dnd_action, data&)> finish_fn)
|
||||
{
|
||||
impl_->drop_finished = finish_fn;
|
||||
}
|
||||
|
||||
|
||||
dragdrop::data::data():
|
||||
dragdrop::data::data(dnd_action requested_action):
|
||||
real_data_(new detail::dragdrop_data)
|
||||
{
|
||||
real_data_->requested_action = requested_action;
|
||||
}
|
||||
|
||||
dragdrop::data::~data()
|
||||
@ -1277,4 +1287,4 @@ namespace nana
|
||||
{
|
||||
real_data_->files.emplace_back(std::move(path));
|
||||
}
|
||||
}//end namespace nana
|
||||
}//end namespace nana
|
||||
|
||||
@ -163,7 +163,8 @@ namespace nana
|
||||
bld_fgcolor = fgcolor.blend(highlighted, 0.6);
|
||||
break;
|
||||
case element_state::disabled:
|
||||
bld_bgcolor = bld_fgcolor = static_cast<color_rgb>(0xb2b7bc);
|
||||
bld_bgcolor = static_cast<color_rgb>(0xE0E0E0);
|
||||
bld_fgcolor = static_cast<color_rgb>(0x999A9E);
|
||||
break;
|
||||
default:
|
||||
//Leave things as they are
|
||||
|
||||
@ -1099,7 +1099,12 @@ namespace nana
|
||||
window owner;
|
||||
bool open_or_save;
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
bool allow_multi_select;
|
||||
std::vector<std::string> files;
|
||||
#else
|
||||
std::string file;
|
||||
#endif
|
||||
std::string title;
|
||||
std::string path;
|
||||
std::vector<filter> filters;
|
||||
@ -1116,6 +1121,7 @@ namespace nana
|
||||
impl_->owner = owner;
|
||||
impl_->open_or_save = open;
|
||||
#if defined(NANA_WINDOWS)
|
||||
impl_->allow_multi_select = false;
|
||||
auto len = ::GetCurrentDirectory(0, nullptr);
|
||||
if(len)
|
||||
{
|
||||
@ -1172,7 +1178,11 @@ namespace nana
|
||||
|
||||
filebox& filebox::init_file(const std::string& ifstr)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
impl_->files = {ifstr};
|
||||
#else
|
||||
impl_->file = ifstr;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1183,22 +1193,41 @@ namespace nana
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string filebox::path() const
|
||||
const std::string& filebox::path() const
|
||||
{
|
||||
return impl_->path;
|
||||
}
|
||||
|
||||
std::string filebox::file() const
|
||||
#if defined(NANA_WINDOWS)
|
||||
const std::string& filebox::file() const
|
||||
{
|
||||
if(impl_->files.empty())
|
||||
{
|
||||
static const std::string empty = "";
|
||||
return empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return impl_->files.front();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string>& filebox::files() const
|
||||
{
|
||||
return impl_->files;
|
||||
}
|
||||
#else
|
||||
const std::string& filebox::file() const
|
||||
{
|
||||
return impl_->file;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool filebox::show() const
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
auto winitfile = to_wstring(impl_->file);
|
||||
std::wstring wfile(winitfile);
|
||||
wfile.resize(520);
|
||||
std::wstring wfile(impl_->files.empty() ? L"" : to_wstring(impl_->files.front()));
|
||||
wfile.resize(impl_->allow_multi_select ? (520 + 32*256) : 520);
|
||||
|
||||
OPENFILENAME ofn;
|
||||
memset(&ofn, 0, sizeof ofn);
|
||||
@ -1263,6 +1292,10 @@ namespace nana
|
||||
if (!impl_->open_or_save)
|
||||
ofn.Flags = OFN_OVERWRITEPROMPT; //Overwrite prompt if it is save mode
|
||||
ofn.Flags |= OFN_NOCHANGEDIR;
|
||||
if(impl_->allow_multi_select)
|
||||
{
|
||||
ofn.Flags |= (OFN_ALLOWMULTISELECT | OFN_EXPLORER);
|
||||
}
|
||||
|
||||
{
|
||||
internal_revert_guard revert;
|
||||
@ -1270,8 +1303,33 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
wfile.resize(std::wcslen(wfile.data()));
|
||||
impl_->file = to_utf8(wfile);
|
||||
if(impl_->allow_multi_select)
|
||||
{
|
||||
wchar_t* str = ofn.lpstrFile;
|
||||
std::wstring dir = str;
|
||||
str += (dir.length() + 1);
|
||||
impl_->files.clear();
|
||||
while(*str)
|
||||
{
|
||||
std::wstring filename = str;
|
||||
std::wstring file_path = dir + L"\\" + filename;
|
||||
impl_->files.emplace_back(to_utf8(file_path));
|
||||
str += (filename.length() + 1);
|
||||
}
|
||||
impl_->path = to_utf8(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
wfile.resize(std::wcslen(wfile.data()));
|
||||
auto file = to_utf8(wfile);
|
||||
impl_->files = {file};
|
||||
auto tpos = file.find_last_of("\\/");
|
||||
if(tpos != file.npos)
|
||||
impl_->path = file.substr(0, tpos);
|
||||
else
|
||||
impl_->path.clear();
|
||||
}
|
||||
|
||||
#elif defined(NANA_POSIX)
|
||||
using mode = filebox_implement::mode;
|
||||
filebox_implement fb(impl_->owner, (impl_->open_or_save ? mode::open_file : mode::write_file), impl_->title);
|
||||
@ -1300,16 +1358,23 @@ namespace nana
|
||||
API::modal_window(fb);
|
||||
if(false == fb.file(impl_->file))
|
||||
return false;
|
||||
#endif
|
||||
auto tpos = impl_->file.find_last_of("\\/");
|
||||
if(tpos != impl_->file.npos)
|
||||
impl_->path = impl_->file.substr(0, tpos);
|
||||
else
|
||||
impl_->path.clear();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}//end class filebox
|
||||
|
||||
}
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
void filebox::allow_multi_select(bool allow)
|
||||
{
|
||||
impl_->allow_multi_select = allow;
|
||||
}
|
||||
#endif
|
||||
//end class filebox
|
||||
|
||||
//class directory picker
|
||||
struct folderbox::implement
|
||||
|
||||
@ -962,7 +962,6 @@ namespace API
|
||||
restrict::wd_manager().update(reinterpret_cast<basic_window*>(wd), false, true);
|
||||
}
|
||||
|
||||
|
||||
void window_caption(window wd, const std::string& title_utf8)
|
||||
{
|
||||
throw_not_utf8(title_utf8);
|
||||
|
||||
@ -85,9 +85,13 @@ namespace nana{ namespace drawerbase
|
||||
graph.text_metrics(txt_px, descent, ileading);
|
||||
txt_px += (descent + 2);
|
||||
|
||||
auto e_state = API::element_state(*wdg);
|
||||
if(!wdg->enabled())
|
||||
e_state = element_state::disabled;
|
||||
|
||||
impl_->crook.draw(graph,
|
||||
impl_->scheme_ptr->square_bgcolor.get(wdg->bgcolor()), impl_->scheme_ptr->square_border_color.get(wdg->fgcolor()),
|
||||
rectangle(0, txt_px > 16 ? (txt_px - 16) / 2 : 0, 16, 16), API::element_state(*wdg));
|
||||
rectangle(0, txt_px > 16 ? (txt_px - 16) / 2 : 0, 16, 16), e_state);
|
||||
}
|
||||
|
||||
void drawer::mouse_down(graph_reference graph, const arg_mouse&)
|
||||
|
||||
@ -36,6 +36,7 @@ namespace nana{
|
||||
{
|
||||
label caption;
|
||||
align caption_align{ align::left };
|
||||
background_mode caption_mode{ background_mode::blending };
|
||||
place place_content;
|
||||
unsigned gap{2};
|
||||
std::string usr_div_str;
|
||||
@ -154,7 +155,7 @@ namespace nana{
|
||||
return *impl_->options.back();
|
||||
}
|
||||
|
||||
void group::caption_align(align position)
|
||||
group& group::caption_align(align position)
|
||||
{
|
||||
if (position != impl_->caption_align)
|
||||
{
|
||||
@ -163,6 +164,32 @@ namespace nana{
|
||||
impl_->place_content.collocate();
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
group& group::caption_background_mode(background_mode mode)
|
||||
{
|
||||
if (mode != impl_->caption_mode)
|
||||
{
|
||||
impl_->caption_mode = mode;
|
||||
switch (mode)
|
||||
{
|
||||
case background_mode::none:
|
||||
impl_->caption.bgcolor(this->bgcolor());
|
||||
impl_->caption.transparent(false);
|
||||
break;
|
||||
case background_mode::blending:
|
||||
impl_->caption.transparent(true);
|
||||
impl_->caption.bgcolor(API::bgcolor(this->parent()).blend(colors::black, 0.025));
|
||||
break;
|
||||
case background_mode::transparent:
|
||||
impl_->caption.transparent(true);
|
||||
impl_->caption.bgcolor(API::bgcolor(this->parent()).blend(colors::black, 0.025));
|
||||
break;
|
||||
}
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
group& group::radio_mode(bool enable)
|
||||
@ -295,17 +322,20 @@ namespace nana{
|
||||
),
|
||||
3, 3, this->scheme().border, true, this->bgcolor());
|
||||
|
||||
auto opt_r = API::window_rectangle(impl_->caption);
|
||||
if (opt_r)
|
||||
if (background_mode::blending == impl_->caption_mode)
|
||||
{
|
||||
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width + 4, static_cast<unsigned>(top_round_line - opt_r->y) } };
|
||||
auto opt_r = API::window_rectangle(impl_->caption);
|
||||
if (opt_r)
|
||||
{
|
||||
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width + 4, static_cast<unsigned>(top_round_line - opt_r->y) } };
|
||||
|
||||
grad_r.y += top_round_line*2 / 3;
|
||||
grad_r.x -= 2;
|
||||
grad_r.y += top_round_line * 2 / 3;
|
||||
grad_r.x -= 2;
|
||||
|
||||
graph.gradual_rectangle(grad_r,
|
||||
API::bgcolor(this->parent()), this->bgcolor(), true
|
||||
);
|
||||
graph.gradual_rectangle(grad_r,
|
||||
API::bgcolor(this->parent()), this->bgcolor(), true
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ namespace nana
|
||||
if (!_m_foreach_visual_line(graph, rs))
|
||||
break;
|
||||
|
||||
rs.pos.y += static_cast<int>(rs.vslines.back().extent_height_px);
|
||||
//Now the y-position of rs has been modified to next line.
|
||||
}
|
||||
|
||||
if (transient_.current_font != pre_font)
|
||||
@ -531,10 +531,6 @@ namespace nana
|
||||
|
||||
bool _m_foreach_visual_line(graph_reference graph, render_status& rs)
|
||||
{
|
||||
std::wstring text;
|
||||
|
||||
content_element_iterator block_start;
|
||||
|
||||
auto const bottom = static_cast<int>(graph.height()) - 1;
|
||||
|
||||
for (auto & vsline : rs.vslines)
|
||||
|
||||
@ -2002,7 +2002,7 @@ namespace nana {
|
||||
|
||||
auto fgcolor = scheme_->foreground.get_color();
|
||||
if (!API::window_enabled(window_))
|
||||
fgcolor.blend(bgcolor, 0.5);
|
||||
fgcolor = fgcolor.blend(bgcolor, 0.5); //Thank to besh81 for getting the fgcolor to be changed
|
||||
|
||||
if (API::widget_borderless(window_))
|
||||
graph_.rectangle(false, bgcolor);
|
||||
|
||||
@ -758,6 +758,10 @@ namespace nana
|
||||
|
||||
void trigger::mouse_move(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
// check if slider is disabled
|
||||
if(!API::get_widget(arg.window_handle)->enabled())
|
||||
return; // do nothing
|
||||
|
||||
bool updated = false;
|
||||
if (model_ptr_->if_trace_slider())
|
||||
{
|
||||
|
||||
@ -111,11 +111,11 @@ namespace nana{ namespace paint
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open(const std::experimental::filesystem::path& filename) override
|
||||
bool open(const std::filesystem::path& filename) override
|
||||
{
|
||||
std::ifstream ifs(filename.string(), std::ios::binary);
|
||||
|
||||
auto const bytes = static_cast<unsigned>(std::experimental::filesystem::file_size(filename));
|
||||
auto const bytes = static_cast<unsigned>(std::filesystem::file_size(filename));
|
||||
if (ifs && (bytes > static_cast<int>(sizeof(bitmap_file_header))))
|
||||
{
|
||||
std::unique_ptr<char[]> buffer{ new char[bytes] };
|
||||
|
||||
@ -241,7 +241,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
bool open(const std::experimental::filesystem::path& ico_file) override
|
||||
bool open(const std::filesystem::path& ico_file) override
|
||||
{
|
||||
std::ifstream file(ico_file.string(), std::ios::binary);
|
||||
if (!file.is_open()) return false;
|
||||
@ -290,7 +290,7 @@ public:
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
std::experimental::filesystem::path path_;
|
||||
std::filesystem::path path_;
|
||||
#if defined(NANA_WINDOWS)
|
||||
void* native_handle_{nullptr};
|
||||
#endif
|
||||
|
||||
@ -29,7 +29,7 @@ namespace nana{ namespace paint
|
||||
:public image::image_impl_interface
|
||||
{
|
||||
public:
|
||||
bool open(const std::experimental::filesystem::path& filename) override
|
||||
bool open(const std::filesystem::path& filename) override
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
SHFILEINFO sfi;
|
||||
|
||||
@ -47,7 +47,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
public:
|
||||
bool open(const std::experimental::filesystem::path& jpeg_file) override
|
||||
bool open(const std::filesystem::path& jpeg_file) override
|
||||
{
|
||||
auto fp = ::fopen(to_osmbstr(to_utf8(jpeg_file.native())).c_str(), "rb");
|
||||
if(nullptr == fp) return false;
|
||||
|
||||
@ -123,7 +123,7 @@ namespace nana
|
||||
delete[] row_ptrs;
|
||||
}
|
||||
public:
|
||||
bool open(const std::experimental::filesystem::path& png_file) override
|
||||
bool open(const std::filesystem::path& png_file) override
|
||||
{
|
||||
auto fp = ::fopen(to_osmbstr(to_utf8(png_file.native())).c_str(), "rb");
|
||||
if(nullptr == fp) return false;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <nana/push_ignore_diagnostic>
|
||||
#include <nana/paint/detail/image_process_provider.hpp>
|
||||
|
||||
#include <nana/paint/detail/image_processor.hpp>
|
||||
#include "image_processor.hpp"
|
||||
|
||||
namespace nana
|
||||
{
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
|
||||
#ifndef NANA_PAINT_DETAIL_IMAGE_PROCESSOR_HPP
|
||||
#define NANA_PAINT_DETAIL_IMAGE_PROCESSOR_HPP
|
||||
#include "../image_process_interface.hpp"
|
||||
#include <nana/paint/pixel_buffer.hpp>
|
||||
#include <nana/paint/image_process_interface.hpp>
|
||||
#include <nana/paint/detail/native_paint_interface.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
@ -421,15 +421,19 @@ namespace detail
|
||||
{
|
||||
virtual void process(paint::pixel_buffer & pixbuf, const nana::point& pos_beg, const nana::point& pos_end, const ::nana::color& clr, double fade_rate) const
|
||||
{
|
||||
//Return if it is completely transparent
|
||||
if (fade_rate <= 0)
|
||||
return;
|
||||
|
||||
auto rgb_color = clr.px_color().value;
|
||||
const std::size_t bytes_pl = pixbuf.bytes_per_line();
|
||||
|
||||
unsigned char * fade_table = nullptr;
|
||||
std::unique_ptr<unsigned char[]> autoptr;
|
||||
nana::pixel_argb_t rgb_imd = {};
|
||||
if(fade_rate != 0.0)
|
||||
if(fade_rate < 1)
|
||||
{
|
||||
autoptr = detail::alloc_fade_table(1 - fade_rate);
|
||||
autoptr = detail::alloc_fade_table(1.0 - fade_rate);
|
||||
fade_table = autoptr.get();
|
||||
rgb_imd.value = rgb_color;
|
||||
rgb_imd = detail::fade_color_intermedia(rgb_imd, fade_table);
|
||||
@ -38,7 +38,7 @@
|
||||
#include "detail/image_ico_resource.hpp"
|
||||
#include "detail/image_ico.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace nana
|
||||
{
|
||||
|
||||
@ -47,7 +47,7 @@ namespace nana
|
||||
std::uint16_t string_offset; //from start of storage area
|
||||
};
|
||||
public:
|
||||
using path_type = ::std::experimental::filesystem::path;
|
||||
using path_type = ::std::filesystem::path;
|
||||
|
||||
truetype(const path_type& filename)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user