Merge pull request #5 from cnjinhao/develop-1.7

Develop 1.7
This commit is contained in:
besh81 2019-01-18 17:12:52 +01:00 committed by GitHub
commit d32d308d4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 489 additions and 272 deletions

View File

@ -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

View File

@ -59,6 +59,7 @@ set(NANA_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source)
set(NANA_SOURCE_SUBDIRS
/.
/detail
/detail/posix
/filesystem
/gui
/gui/detail

View File

@ -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

View File

@ -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_;
};

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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),

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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_;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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&)

View File

@ -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
);
}
}
});
}

View File

@ -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)

View File

@ -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);

View File

@ -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())
{

View File

@ -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] };

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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
{

View File

@ -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);

View File

@ -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
{

View File

@ -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)
{