commit
1468d1836c
@ -8,11 +8,11 @@ cache:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: CXX=g++-5 CC=gcc-5
|
||||
- env: CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
- g++-8
|
||||
- libjpeg8-dev
|
||||
- libpng-dev
|
||||
- libasound2-dev
|
||||
@ -44,7 +44,7 @@ matrix:
|
||||
|
||||
before_install:
|
||||
- cd ..
|
||||
- git clone --depth=1 --branch=cmake-dev https://github.com/qPCR4vir/nana-demo.git nana-demo
|
||||
- git clone --depth=1 --branch=hotfix 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
|
||||
|
@ -254,7 +254,7 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
path relative_path() const;
|
||||
path parent_path() const;
|
||||
path filename() const;
|
||||
//path stem() const;
|
||||
path stem() const;
|
||||
path extension() const;
|
||||
|
||||
// query
|
||||
@ -290,6 +290,8 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
// std::u16string generic_u16string() const;
|
||||
// std::u32string generic_u32string() const;
|
||||
|
||||
path lexically_normal() const;
|
||||
|
||||
//appends
|
||||
path& operator/=(const path& other);
|
||||
|
||||
@ -544,6 +546,9 @@ namespace std {
|
||||
|
||||
path canonical(const path& p);
|
||||
path canonical(const path& p, std::error_code& err);
|
||||
|
||||
path weakly_canonical(const path& p);
|
||||
path weakly_canonical(const path& p, std::error_code& err);
|
||||
#endif
|
||||
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
|
||||
|
@ -127,6 +127,9 @@ namespace detail
|
||||
basic_window * seek_non_lite_widget_ancestor() const;
|
||||
|
||||
void set_action(mouse_action);
|
||||
|
||||
/// Only refresh when the root of window is in lazy-updating mode
|
||||
bool try_lazy_update(bool try_refresh);
|
||||
public:
|
||||
/// Override event_holder
|
||||
bool set_events(const std::shared_ptr<general_events>&) override;
|
||||
@ -176,8 +179,7 @@ namespace detail
|
||||
bool ignore_mouse_focus : 1; ///< A flag indicates whether the widget accepts focus when clicking on it
|
||||
bool space_click_enabled : 1; ///< A flag indicates whether enable mouse_down/click/mouse_up when pressing and releasing whitespace key.
|
||||
bool draggable : 1;
|
||||
bool ignore_child_mapping : 1;
|
||||
unsigned Reserved :16;
|
||||
unsigned Reserved : 17;
|
||||
unsigned char tab; ///< indicate a window that can receive the keyboard TAB
|
||||
mouse_action action;
|
||||
mouse_action action_before;
|
||||
@ -205,11 +207,14 @@ namespace detail
|
||||
{
|
||||
struct attr_root_tag
|
||||
{
|
||||
bool ime_enabled{ false };
|
||||
bool lazy_update{ false }; ///< Indicates whether the window is in lazy-updating mode.
|
||||
|
||||
container update_requesters; ///< Container for lazy-updating requesting windows.
|
||||
container tabstop;
|
||||
std::vector<edge_nimbus_action> effects_edge_nimbus;
|
||||
basic_window* focus{nullptr};
|
||||
basic_window* menubar{nullptr};
|
||||
bool ime_enabled{false};
|
||||
cursor state_cursor{nana::cursor::arrow};
|
||||
basic_window* state_cursor_window{ nullptr };
|
||||
|
||||
@ -223,8 +228,6 @@ namespace detail
|
||||
update_state upd_state;
|
||||
dragdrop_status dnd_state{ dragdrop_status::not_ready };
|
||||
|
||||
container mapping_requester; ///< Children which are ignored to mapping
|
||||
|
||||
union
|
||||
{
|
||||
attr_root_tag * root;
|
||||
|
@ -99,7 +99,11 @@ namespace detail
|
||||
|
||||
bool show(core_window_t* wd, bool visible);
|
||||
|
||||
core_window_t* find_window(native_window_type root, const point& pos);
|
||||
//find a widget window at specified position
|
||||
//@param root A root window
|
||||
//@param pos Position
|
||||
//@param ignore_captured A flag indicates whether to ignore redirecting the result to its captured window. If this paramter is true, it returns the window at the position, if the parameter is false, it returns the captured window if the captured window don't ignore children.
|
||||
core_window_t* find_window(native_window_type root, const point& pos, bool ignore_captured = false);
|
||||
|
||||
//move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window
|
||||
bool move(core_window_t*, int x, int y, bool passive);
|
||||
@ -116,7 +120,6 @@ namespace detail
|
||||
void refresh_tree(core_window_t*);
|
||||
|
||||
void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
|
||||
void map_requester(core_window_t*);
|
||||
|
||||
bool set_parent(core_window_t* wd, core_window_t* new_parent);
|
||||
core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason);
|
||||
|
@ -225,8 +225,12 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
//Because of No wide character version of POSIX
|
||||
#if defined(NANA_POSIX)
|
||||
const char* separators = "/";
|
||||
const char separator = '/';
|
||||
const char* punt = ".";
|
||||
#else
|
||||
const wchar_t* separators = L"/\\";
|
||||
const char separator = '\\';
|
||||
const wchar_t* punt = L".";
|
||||
#endif
|
||||
|
||||
//class file_status
|
||||
@ -453,6 +457,22 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
return{ pathstr_ };
|
||||
}
|
||||
|
||||
path path::stem() const
|
||||
{
|
||||
auto pos = pathstr_.find_last_of(separators);
|
||||
auto ext = pathstr_.find_last_of(punt);
|
||||
|
||||
if (pos == pathstr_.npos)
|
||||
pos = 0;
|
||||
else
|
||||
pos++;
|
||||
|
||||
if (ext == pathstr_.npos || ext < pos)
|
||||
return path(pathstr_.substr(pos));
|
||||
else
|
||||
return path(pathstr_.substr(pos, ext-pos));
|
||||
}
|
||||
|
||||
void path::clear() noexcept
|
||||
{
|
||||
pathstr_.clear();
|
||||
@ -550,6 +570,71 @@ namespace nana { namespace experimental { namespace filesystem
|
||||
std::replace(str.begin(), str.end(), '\\', '/'); // uppss ... revise this !!!!!
|
||||
return to_utf8(str);
|
||||
}
|
||||
|
||||
path path::lexically_normal() const
|
||||
{
|
||||
if (pathstr_.empty())
|
||||
return *this;
|
||||
|
||||
std::vector<path> elements;
|
||||
path temp{ pathstr_ };
|
||||
while (!temp.empty())
|
||||
{
|
||||
elements.emplace_back(temp.filename());
|
||||
temp.remove_filename();
|
||||
}
|
||||
|
||||
auto start = elements.begin();
|
||||
auto last = elements.end();
|
||||
auto stop = last--;
|
||||
for (auto itr(start); itr != stop; ++itr)
|
||||
{
|
||||
// ignore "." except at start and last
|
||||
if (itr->native().size() == 1
|
||||
&& (itr->native())[0] == '.'
|
||||
&& itr != start
|
||||
&& itr != last) continue;
|
||||
|
||||
// ignore a name and following ".."
|
||||
if (!temp.empty()
|
||||
&& itr->native().size() == 2
|
||||
&& (itr->native())[0] == '.'
|
||||
&& (itr->native())[1] == '.') // dot dot
|
||||
{
|
||||
string_type lf(temp.filename().native());
|
||||
if (lf.size() > 0
|
||||
&& (lf.size() != 1
|
||||
|| (lf[0] != '.'
|
||||
&& (lf[0] != '/' && lf[0] != '\\')))
|
||||
&& (lf.size() != 2
|
||||
|| (lf[0] != '.'
|
||||
&& lf[1] != '.'
|
||||
# ifdef NANA_WINDOWS
|
||||
&& lf[1] != ':'
|
||||
# endif
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
temp.remove_filename();
|
||||
auto next = itr;
|
||||
if (temp.empty() && ++next != stop
|
||||
&& next == last && last->string() == ".")
|
||||
{
|
||||
temp /= ".";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
temp /= *itr;
|
||||
};
|
||||
|
||||
if (temp.empty())
|
||||
temp = ".";
|
||||
return temp;
|
||||
}
|
||||
|
||||
path & path::operator/=(const path& p)
|
||||
{
|
||||
if (p.empty())
|
||||
@ -1254,6 +1339,81 @@ namespace std
|
||||
{
|
||||
return canonical(p, &err);
|
||||
}
|
||||
|
||||
bool try_throw(int err_val, const path& p, std::error_code* ec, const char* message)
|
||||
{
|
||||
if (0 == err_val)
|
||||
{
|
||||
if (ec) ec->clear();
|
||||
}
|
||||
else
|
||||
{ //error
|
||||
if (nullptr == ec)
|
||||
throw (filesystem_error(
|
||||
"nana::filesystem::canonical", p,
|
||||
error_code(err_val, generic_category())));
|
||||
else
|
||||
ec->assign(err_val, system_category());
|
||||
}
|
||||
return err_val != 0;
|
||||
}
|
||||
|
||||
path weakly_canonical(const path& p, std::error_code* err)
|
||||
{
|
||||
path head{ p };
|
||||
|
||||
std::error_code tmp_err;
|
||||
std::vector<path> elements;
|
||||
while (!head.empty())
|
||||
{
|
||||
auto head_status = status(head, tmp_err);
|
||||
|
||||
if (head_status.type() == file_type::unknown)
|
||||
{
|
||||
if (try_throw(static_cast<int>(errc::invalid_argument), head, err, "nana::filesystem::weakly_canonical"))
|
||||
return path{};
|
||||
}
|
||||
if (head_status.type() != file_type::not_found)
|
||||
break;
|
||||
|
||||
elements.emplace_back(head.filename());
|
||||
head.remove_filename();
|
||||
}
|
||||
|
||||
bool tail_has_dots = false;
|
||||
path tail;
|
||||
|
||||
for (auto & e : elements)
|
||||
{
|
||||
tail /= e;
|
||||
// for a later optimization, track if any dot or dot-dot elements are present
|
||||
if (e.native().size() <= 2
|
||||
&& e.native()[0] == '.'
|
||||
&& (e.native().size() == 1 || e.native()[1] == '.'))
|
||||
tail_has_dots = true;
|
||||
}
|
||||
|
||||
if (head.empty())
|
||||
return p.lexically_normal();
|
||||
head = canonical(head, tmp_err);
|
||||
if (try_throw(tmp_err.value(), head, err, "nana::filesystem::weakly_canonical"))
|
||||
return path();
|
||||
return tail.empty()
|
||||
? head
|
||||
: (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element
|
||||
? (head / tail).lexically_normal()
|
||||
: head / tail);
|
||||
}
|
||||
|
||||
path weakly_canonical(const path& p)
|
||||
{
|
||||
return weakly_canonical(p, nullptr);
|
||||
}
|
||||
|
||||
path weakly_canonical(const path& p, std::error_code& err)
|
||||
{
|
||||
return weakly_canonical(p, &err);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW)
|
||||
|
@ -336,6 +336,43 @@ namespace nana
|
||||
flags.action = act;
|
||||
}
|
||||
|
||||
|
||||
bool basic_window::try_lazy_update(bool try_refresh)
|
||||
{
|
||||
if (drawer.graphics.empty())
|
||||
return true;
|
||||
|
||||
if (!this->root_widget->other.attribute.root->lazy_update)
|
||||
return false;
|
||||
|
||||
if (nullptr == effect.bground)
|
||||
{
|
||||
if (try_refresh)
|
||||
{
|
||||
flags.refreshing = true;
|
||||
drawer.refresh();
|
||||
flags.refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = this->root_widget->other.attribute.root->update_requesters.cbegin(); i != this->root_widget->other.attribute.root->update_requesters.cend();)
|
||||
{
|
||||
auto req = *i;
|
||||
//Avoid redundancy, don't insert the window if it or its ancestor window already exist in the container.
|
||||
if ((req == this) || req->is_ancestor_of(this))
|
||||
return true;
|
||||
|
||||
//If there is a window which is a child or child's child of the window, remove it.
|
||||
if (this->is_ancestor_of(req))
|
||||
i = this->root_widget->other.attribute.root->update_requesters.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
this->root_widget->other.attribute.root->update_requesters.push_back(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r)
|
||||
{
|
||||
pos_owner = pos_root = r.position();
|
||||
@ -390,7 +427,6 @@ namespace nana
|
||||
flags.ignore_menubar_focus = false;
|
||||
flags.ignore_mouse_focus = false;
|
||||
flags.space_click_enabled = false;
|
||||
flags.ignore_child_mapping = false;
|
||||
|
||||
visible = false;
|
||||
|
||||
|
@ -641,13 +641,8 @@ namespace nana
|
||||
if (update_state::none == wd->other.upd_state)
|
||||
wd->other.upd_state = update_state::lazy;
|
||||
|
||||
auto ignore_mapping_value = wd->flags.ignore_child_mapping;
|
||||
wd->flags.ignore_child_mapping = true;
|
||||
|
||||
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
|
||||
|
||||
wd->flags.ignore_child_mapping = ignore_mapping_value;
|
||||
|
||||
bool good_wd = false;
|
||||
if(wd_manager().available(wd))
|
||||
{
|
||||
@ -658,10 +653,7 @@ namespace nana
|
||||
wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code));
|
||||
}
|
||||
else
|
||||
{
|
||||
wd_manager().map_requester(wd);
|
||||
wd->other.upd_state = update_state::none;
|
||||
}
|
||||
|
||||
good_wd = true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/window_layout.hpp>
|
||||
#include <nana/gui/detail/element_store.hpp>
|
||||
#include "inner_fwd_implement.hpp"
|
||||
#include <errno.h>
|
||||
@ -555,6 +556,27 @@ namespace detail
|
||||
context.is_alt_pressed = false;
|
||||
}
|
||||
|
||||
class window_proc_guard
|
||||
{
|
||||
public:
|
||||
window_proc_guard(detail::basic_window* wd) :
|
||||
root_wd_(wd)
|
||||
{
|
||||
root_wd_->other.attribute.root->lazy_update = true;
|
||||
}
|
||||
|
||||
~window_proc_guard()
|
||||
{
|
||||
if (!bedrock::instance().wd_manager().available(root_wd_))
|
||||
return;
|
||||
|
||||
root_wd_->other.attribute.root->lazy_update = false;
|
||||
root_wd_->other.attribute.root->update_requesters.clear();
|
||||
}
|
||||
private:
|
||||
detail::basic_window* const root_wd_;
|
||||
};
|
||||
|
||||
void window_proc_for_xevent(Display* /*display*/, XEvent& xevent)
|
||||
{
|
||||
typedef detail::bedrock::core_window_t core_window_t;
|
||||
@ -569,10 +591,13 @@ namespace detail
|
||||
|
||||
if(root_runtime)
|
||||
{
|
||||
auto msgwnd = root_runtime->window;
|
||||
auto const root_wd = root_runtime->window;
|
||||
auto msgwnd = root_wd;
|
||||
window_proc_guard wp_guard{ root_wd };
|
||||
|
||||
auto& context = *brock.get_thread_context(msgwnd->thread_id);
|
||||
|
||||
auto pre_event_window = context.event_window;
|
||||
auto const pre_event_window = context.event_window;
|
||||
auto pressed_wd = root_runtime->condition.pressed;
|
||||
auto pressed_wd_space = root_runtime->condition.pressed_by_space;
|
||||
auto hovered_wd = root_runtime->condition.hovered;
|
||||
@ -1190,6 +1215,15 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size())
|
||||
{
|
||||
for (auto wd : root_wd->other.attribute.root->update_requesters)
|
||||
{
|
||||
window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false);
|
||||
wd_manager.map(wd, true);
|
||||
}
|
||||
}
|
||||
|
||||
root_runtime = wd_manager.root_runtime(native_window);
|
||||
if(root_runtime)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <nana/gui.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/window_layout.hpp>
|
||||
#include <nana/gui/detail/element_store.hpp>
|
||||
#include <nana/gui/detail/color_schemes.hpp>
|
||||
#include "inner_fwd_implement.hpp"
|
||||
@ -37,6 +38,7 @@
|
||||
|
||||
#include "bedrock_types.hpp"
|
||||
|
||||
|
||||
typedef void (CALLBACK *win_event_proc_t)(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime);
|
||||
|
||||
namespace nana
|
||||
@ -738,6 +740,27 @@ namespace detail
|
||||
return static_cast<wchar_t>(vkey);
|
||||
}
|
||||
|
||||
class window_proc_guard
|
||||
{
|
||||
public:
|
||||
window_proc_guard(detail::basic_window* wd) :
|
||||
root_wd_(wd)
|
||||
{
|
||||
root_wd_->other.attribute.root->lazy_update = true;
|
||||
}
|
||||
|
||||
~window_proc_guard()
|
||||
{
|
||||
if (!bedrock::instance().wd_manager().available(root_wd_))
|
||||
return;
|
||||
|
||||
root_wd_->other.attribute.root->lazy_update = false;
|
||||
root_wd_->other.attribute.root->update_requesters.clear();
|
||||
}
|
||||
private:
|
||||
detail::basic_window* const root_wd_;
|
||||
};
|
||||
|
||||
LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT window_proc_value = 0;
|
||||
@ -757,6 +780,7 @@ namespace detail
|
||||
bool def_window_proc = false;
|
||||
auto& context = *brock.get_thread_context();
|
||||
|
||||
auto const pre_event_window = context.event_window;
|
||||
auto pressed_wd = root_runtime->condition.pressed;
|
||||
auto pressed_wd_space = root_runtime->condition.pressed_by_space;
|
||||
auto hovered_wd = root_runtime->condition.hovered;
|
||||
@ -766,7 +790,10 @@ namespace detail
|
||||
pmdec.raw_param.wparam = wParam;
|
||||
|
||||
internal_scope_guard lock;
|
||||
auto msgwnd = root_runtime->window;
|
||||
auto const root_wd = root_runtime->window;
|
||||
auto msgwnd = root_wd;
|
||||
|
||||
window_proc_guard wp_guard{ root_wd };
|
||||
|
||||
switch (message)
|
||||
{
|
||||
@ -775,10 +802,7 @@ namespace detail
|
||||
{
|
||||
auto i = root_runtime->wpassoc->accel_commands.find(LOWORD(wParam));
|
||||
if (i != root_runtime->wpassoc->accel_commands.end())
|
||||
{
|
||||
auto fn = i->second;
|
||||
fn();
|
||||
}
|
||||
i->second();
|
||||
}
|
||||
break;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
@ -1092,7 +1116,9 @@ namespace detail
|
||||
//The focus window receives the message in Windows system, it should be redirected to the hovered window
|
||||
::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position
|
||||
auto pointer_wd = ::WindowFromPoint(scr_pos);
|
||||
if (pointer_wd == root_window)
|
||||
|
||||
//Ignore the message if the window is disabled.
|
||||
if ((pointer_wd == root_window) && ::IsWindowEnabled(root_window))
|
||||
{
|
||||
::ScreenToClient(pointer_wd, &scr_pos);
|
||||
auto scrolled_wd = wd_manager.find_window(reinterpret_cast<native_window_type>(pointer_wd), { scr_pos.x, scr_pos.y });
|
||||
@ -1124,7 +1150,7 @@ namespace detail
|
||||
wd_manager.do_lazy_refresh(scrolled_wd, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (pointer_wd != root_window)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
::GetWindowThreadProcessId(pointer_wd, &pid);
|
||||
@ -1450,7 +1476,7 @@ namespace detail
|
||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
if(wParam != VK_MENU) //MUST NOT BE AN ALT
|
||||
{
|
||||
@ -1551,13 +1577,28 @@ namespace detail
|
||||
def_window_proc = true;
|
||||
}
|
||||
|
||||
if (wd_manager.available(root_wd) && root_wd->other.attribute.root->update_requesters.size())
|
||||
{
|
||||
for (auto wd : root_wd->other.attribute.root->update_requesters)
|
||||
{
|
||||
window_layout::paint(wd, window_layout::paint_operation::have_refreshed, false);
|
||||
wd_manager.map(wd, true);
|
||||
}
|
||||
}
|
||||
|
||||
root_runtime = wd_manager.root_runtime(native_window);
|
||||
if(root_runtime)
|
||||
{
|
||||
context.event_window = pre_event_window;
|
||||
root_runtime->condition.pressed = pressed_wd;
|
||||
root_runtime->condition.hovered = hovered_wd;
|
||||
root_runtime->condition.pressed_by_space = pressed_wd_space;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto context = brock.get_thread_context();
|
||||
if(context) context->event_window = pre_event_window;
|
||||
}
|
||||
|
||||
if (!def_window_proc)
|
||||
return 0;
|
||||
|
@ -701,19 +701,40 @@ namespace detail
|
||||
return true;
|
||||
}
|
||||
|
||||
window_manager::core_window_t* window_manager::find_window(native_window_type root, const point& pos)
|
||||
window_manager::core_window_t* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured)
|
||||
{
|
||||
if (nullptr == root)
|
||||
return nullptr;
|
||||
|
||||
if((false == attr_.capture.ignore_children) || (nullptr == attr_.capture.window) || (attr_.capture.window->root != root))
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<mutex_type> lock(mutex_);
|
||||
|
||||
if (ignore_captured || (nullptr == attr_.capture.window))
|
||||
{
|
||||
auto rrt = root_runtime(root);
|
||||
if (rrt && _m_effective(rrt->window, pos))
|
||||
return _m_find(rrt->window, pos);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (attr_.capture.ignore_children)
|
||||
return attr_.capture.window;
|
||||
|
||||
auto rrt = root_runtime(root);
|
||||
if (rrt && _m_effective(rrt->window, pos))
|
||||
{
|
||||
auto target = _m_find(rrt->window, pos);
|
||||
|
||||
auto p = target;
|
||||
while (p)
|
||||
{
|
||||
if (p == attr_.capture.window)
|
||||
return target;
|
||||
p = p->parent;
|
||||
}
|
||||
}
|
||||
|
||||
return attr_.capture.window;
|
||||
}
|
||||
|
||||
@ -980,29 +1001,8 @@ namespace detail
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<mutex_type> lock(mutex_);
|
||||
if (impl_->wd_register.available(wd) && !wd->is_draw_through())
|
||||
{
|
||||
auto parent = wd->parent;
|
||||
while (parent)
|
||||
{
|
||||
if(parent->flags.ignore_child_mapping || parent->flags.refreshing)
|
||||
{
|
||||
auto top = parent;
|
||||
while(parent->parent)
|
||||
{
|
||||
parent = parent->parent;
|
||||
if(parent->flags.ignore_child_mapping || parent->flags.refreshing)
|
||||
top = parent;
|
||||
}
|
||||
|
||||
top->other.mapping_requester.push_back(wd);
|
||||
return;
|
||||
}
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
bedrock::instance().flush_surface(wd, forced, update_area);
|
||||
}
|
||||
}
|
||||
|
||||
//update
|
||||
//@brief: update is used for displaying the screen-off buffer.
|
||||
@ -1027,9 +1027,12 @@ namespace detail
|
||||
if(forced || (false == wd->belong_to_lazy()))
|
||||
{
|
||||
if (!wd->flags.refreshing)
|
||||
{
|
||||
if (!wd->try_lazy_update(redraw))
|
||||
{
|
||||
window_layer::paint(wd, (redraw ? paint_operation::try_refresh : paint_operation::none), false);
|
||||
this->map(wd, forced, update_area);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (forced)
|
||||
@ -1075,40 +1078,29 @@ namespace detail
|
||||
if (wd->visible_parents())
|
||||
{
|
||||
if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen)
|
||||
{
|
||||
if (!wd->try_lazy_update(wd->other.upd_state == core_window_t::update_state::request_refresh))
|
||||
{
|
||||
window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree);
|
||||
this->map(wd, force_copy_to_screen);
|
||||
}
|
||||
}
|
||||
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
|
||||
{
|
||||
//The window is still mapped because of edge nimbus effect.
|
||||
//Avoid duplicate copy if action state is not changed and the window is not focused.
|
||||
if (wd->flags.action != wd->flags.action_before)
|
||||
{
|
||||
if (!wd->try_lazy_update(false))
|
||||
this->map(wd, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent
|
||||
}
|
||||
|
||||
wd->other.upd_state = core_window_t::update_state::none;
|
||||
wd->other.mapping_requester.clear();
|
||||
}
|
||||
|
||||
void window_manager::map_requester(core_window_t* wd)
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<mutex_type> lock(mutex_);
|
||||
|
||||
if (false == impl_->wd_register.available(wd))
|
||||
return;
|
||||
|
||||
if (wd->visible_parents())
|
||||
{
|
||||
for(auto requestor : wd->other.mapping_requester)
|
||||
this->map(requestor, true);
|
||||
}
|
||||
|
||||
wd->other.mapping_requester.clear();
|
||||
}
|
||||
|
||||
bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa)
|
||||
|
@ -1589,7 +1589,7 @@ namespace nana
|
||||
};
|
||||
|
||||
folderbox::folderbox(window owner, const path_type& init_path, std::string title)
|
||||
: impl_(new implement{ owner, fs::canonical(init_path).make_preferred(), title, false})
|
||||
: impl_(new implement{ owner, fs::weakly_canonical(init_path).make_preferred(), title, false})
|
||||
{}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Message Box Class
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -453,7 +453,20 @@ namespace nana
|
||||
default: break;
|
||||
}
|
||||
|
||||
auto bt = ::MessageBoxW(reinterpret_cast<HWND>(API::root(wd_)), to_wstring(sstream_.str()).c_str(), to_wstring(title_).c_str(), type);
|
||||
//Disables the owner window to prevent the owner window processing mouse wheel event
|
||||
//when the message box is showing and scroll the wheel on the owner window.
|
||||
auto native = reinterpret_cast<HWND>(API::root(wd_));
|
||||
BOOL enabled = FALSE;
|
||||
if (native)
|
||||
{
|
||||
enabled = ::IsWindowEnabled(native);
|
||||
if (enabled)
|
||||
::EnableWindow(native, FALSE);
|
||||
}
|
||||
auto bt = ::MessageBoxW(native, to_wstring(sstream_.str()).c_str(), to_wstring(title_).c_str(), type);
|
||||
|
||||
if (native && enabled)
|
||||
::EnableWindow(native, TRUE);
|
||||
|
||||
switch(bt)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Implementation of Place for Layout
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -630,7 +630,8 @@ namespace nana
|
||||
void collocate();
|
||||
|
||||
static division * search_div_name(division* start, const std::string&) noexcept;
|
||||
std::unique_ptr<division> scan_div(place_parts::tokenizer&);
|
||||
|
||||
std::unique_ptr<division> scan_div(place_parts::tokenizer&, bool implicitly_started, const std::string& ignore_duplicate = {});
|
||||
void check_unique(const division*) const;
|
||||
|
||||
//connect the field/dock with div object
|
||||
@ -1987,7 +1988,7 @@ namespace nana
|
||||
|
||||
std::string::size_type tag_pos{ left ? div.find('<', bound.second + 2) : div.rfind('>', bound.first - 2) };
|
||||
if (div.npos == tag_pos)
|
||||
throw std::runtime_error("place report an issue if it throws");
|
||||
throw std::invalid_argument("please report an issue if it throws");
|
||||
|
||||
auto other_bound = get_field_boundary(div, tag_pos);
|
||||
|
||||
@ -2706,7 +2707,9 @@ namespace nana
|
||||
throw std::invalid_argument("nana.place: the type of the " + std::string{pos_strs[pos]} +"th parameter for collapse should be integer.");
|
||||
}
|
||||
|
||||
auto place::implement::scan_div(place_parts::tokenizer& tknizer) -> std::unique_ptr<division>
|
||||
//implicitly_started indicates whether the field in div-text starts without < mark.
|
||||
//ignore_duplicate A field is allowed to have same name if its has an ancestor which name is same with ignore_duplicate.
|
||||
auto place::implement::scan_div(place_parts::tokenizer& tknizer, bool implicitly_started, const std::string& ignore_duplicate) -> std::unique_ptr<division>
|
||||
{
|
||||
using token = place_parts::tokenizer::token ;
|
||||
|
||||
@ -2728,7 +2731,8 @@ namespace nana
|
||||
bool undisplayed = false;
|
||||
bool invisible = false;
|
||||
|
||||
for (token tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read())
|
||||
token tk = token::eof;
|
||||
for (tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read())
|
||||
{
|
||||
switch (tk)
|
||||
{
|
||||
@ -2752,14 +2756,25 @@ namespace nana
|
||||
{
|
||||
auto splitter = new div_splitter(tknizer.number(), this);
|
||||
children.back()->div_next = splitter;
|
||||
|
||||
//Hides the splitter if its left leaf is undisplayed.
|
||||
if (!children.back()->display)
|
||||
splitter->display = false;
|
||||
|
||||
children.emplace_back(std::unique_ptr<division>{ splitter });
|
||||
}
|
||||
break;
|
||||
case token::div_start:
|
||||
{
|
||||
auto div = scan_div(tknizer);
|
||||
auto div = scan_div(tknizer, false, ignore_duplicate);
|
||||
if (!children.empty())
|
||||
{
|
||||
//Hides the splitter if its right leaf is undisplayed.
|
||||
if ((children.back()->kind_of_division == division::kind::splitter) && !div->display)
|
||||
children.back()->display = false;
|
||||
|
||||
children.back()->div_next = div.get();
|
||||
}
|
||||
|
||||
children.emplace_back(std::move(div));
|
||||
}
|
||||
@ -2887,6 +2902,9 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
if (implicitly_started && (tk == token::div_end))
|
||||
throw std::invalid_argument("nana.place: the div-text ends prematurely at " + std::to_string(tknizer.pos()));
|
||||
|
||||
field_gather * attached_field = nullptr;
|
||||
|
||||
//find the field with specified name.
|
||||
@ -2897,8 +2915,31 @@ namespace nana
|
||||
attached_field = i->second;
|
||||
//the field is attached to a division, it means there is another division with same name.
|
||||
if (attached_field->attached)
|
||||
{
|
||||
//The fields are allowed to have a same name. E.g.
|
||||
//place.div("A <B><C>");
|
||||
//place.modify("A", "<B>"); Here the same name B must be allowed, otherwise it throws runtime error.
|
||||
|
||||
bool allow_same_name = false;
|
||||
if (!ignore_duplicate.empty())
|
||||
{
|
||||
auto f = attached_field->attached->div_owner;
|
||||
while (f)
|
||||
{
|
||||
if (f->name == ignore_duplicate)
|
||||
{
|
||||
allow_same_name = true;
|
||||
break;
|
||||
}
|
||||
|
||||
f = f->div_owner;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allow_same_name)
|
||||
throw std::runtime_error("place, the name '" + name + "' is redefined.");
|
||||
}
|
||||
}
|
||||
|
||||
token unmatch = token::width;
|
||||
switch (div_type)
|
||||
@ -2977,7 +3018,16 @@ namespace nana
|
||||
//attach the field to the division
|
||||
div->field = attached_field;
|
||||
if (attached_field)
|
||||
{
|
||||
//Replaces the previous div with the new div which is allowed to have a same name.
|
||||
|
||||
//Detaches the field from the previous div.
|
||||
if (attached_field->attached)
|
||||
attached_field->attached->field = nullptr;
|
||||
|
||||
//Attaches new div
|
||||
attached_field->attached = div.get();
|
||||
}
|
||||
|
||||
if (children.size())
|
||||
{
|
||||
@ -3194,7 +3244,7 @@ namespace nana
|
||||
{
|
||||
place_parts::tokenizer tknizer(div_text.c_str());
|
||||
impl_->disconnect();
|
||||
auto div = impl_->scan_div(tknizer);
|
||||
auto div = impl_->scan_div(tknizer, true);
|
||||
try
|
||||
{
|
||||
impl_->connect(div.get()); //throws if there is a redefined name of field.
|
||||
@ -3263,7 +3313,7 @@ namespace nana
|
||||
try
|
||||
{
|
||||
place_parts::tokenizer tknizer(div_text);
|
||||
auto modified = impl_->scan_div(tknizer);
|
||||
auto modified = impl_->scan_div(tknizer, true, name);
|
||||
auto modified_ptr = modified.get();
|
||||
modified_ptr->name = name;
|
||||
|
||||
|
@ -1403,7 +1403,7 @@ namespace API
|
||||
::nana::point clipos{pos};
|
||||
interface_type::calc_window_point(wd, clipos);
|
||||
return reinterpret_cast<window>(
|
||||
restrict::wd_manager().find_window(wd, clipos));
|
||||
restrict::wd_manager().find_window(wd, clipos, true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Combox Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -676,6 +676,9 @@ namespace nana
|
||||
{
|
||||
auto * editor = drawer_->editor();
|
||||
editor->mouse_pressed(arg);
|
||||
|
||||
//Pops up the droplist only if left button is clicked
|
||||
if(arg.is_left_button())
|
||||
drawer_->open_lister_if_push_button_positioned();
|
||||
|
||||
drawer_->draw();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* A Tabbar Implementation
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -1291,7 +1291,8 @@ namespace nana
|
||||
|
||||
void trigger::mouse_down(graph_reference, const arg_mouse& arg)
|
||||
{
|
||||
if(layouter_->press())
|
||||
//Activates the tab only if left button is clicked.
|
||||
if(arg.is_left_button() && layouter_->press())
|
||||
{
|
||||
if(false == layouter_->active_by_trace(arg))
|
||||
layouter_->toolbox_answer(arg);
|
||||
@ -1593,10 +1594,10 @@ namespace nana
|
||||
API::dev::lazy_refresh();
|
||||
}
|
||||
|
||||
void driver::mouse_down(graph_reference graph, const arg_mouse&)
|
||||
void driver::mouse_down(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
auto & indexes = model_->get_indexes();
|
||||
if ((indexes.hovered_pos == model_->npos) || (indexes.active_pos == indexes.hovered_pos))
|
||||
if ((indexes.hovered_pos == model_->npos) || (indexes.active_pos == indexes.hovered_pos) || !arg.is_left_button())
|
||||
return;
|
||||
|
||||
if (indexes.active_pos != indexes.hovered_pos)
|
||||
|
@ -963,6 +963,9 @@ namespace nana
|
||||
if(text_r.right() > visible_w_pixels())
|
||||
{
|
||||
node_state.tooltip = new tooltip_window(data.widget_ptr->handle(), text_r);
|
||||
|
||||
//PR#406 Error Flynn's contribution
|
||||
//fix: tooltip window doesn't have tree scheme & typeface
|
||||
API::dev::set_scheme(node_state.tooltip->handle(), API::dev::get_scheme(data.widget_ptr->handle()));
|
||||
node_state.tooltip->typeface(data.widget_ptr->typeface());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user