Merge remote-tracking branch 'nana_jinhao/hotfixes-1.0.2' into hotfixes-1.0.2

This commit is contained in:
qPCR4vir
2015-07-10 12:57:08 +02:00
14 changed files with 342 additions and 303 deletions

View File

@@ -84,6 +84,7 @@ namespace nana
end_of_medium = 0x19, //Ctrl+Y end_of_medium = 0x19, //Ctrl+Y
substitute = 0x1A, //Ctrl+Z substitute = 0x1A, //Ctrl+Z
escape = 0x1B, escape = 0x1B,
space = 0x20, //Space
//The following names are intuitive name of ASCII control codes //The following names are intuitive name of ASCII control codes
select_all = start_of_headline, select_all = start_of_headline,

View File

@@ -118,9 +118,11 @@ namespace detail
bool is_ancestor_of(const basic_window* wd) const; bool is_ancestor_of(const basic_window* wd) const;
bool visible_parents() const; bool visible_parents() const;
bool displayed() const;
bool belong_to_lazy() const; bool belong_to_lazy() const;
const basic_window * child_caret() const; //Returns a child which owns a caret
bool is_draw_through() const; ///< Determines whether it is a draw-through window. bool is_draw_through() const; // Determines whether it is a draw-through window.
public: public:
//Override event_holder //Override event_holder
bool set_events(const std::shared_ptr<general_events>&) override; bool set_events(const std::shared_ptr<general_events>&) override;

View File

@@ -23,12 +23,18 @@ namespace nana
{ {
class widget; class widget;
namespace detail
{
class drawer;
}
class drawer_trigger class drawer_trigger
: ::nana::noncopyable, ::nana::nonmovable : ::nana::noncopyable, ::nana::nonmovable
{ {
friend class detail::drawer;
public: public:
typedef widget& widget_reference; using widget_reference = widget&;
typedef paint::graphics& graph_reference; using graph_reference = paint::graphics&;
virtual ~drawer_trigger(); virtual ~drawer_trigger();
virtual void attached(widget_reference, graph_reference); //none-const virtual void attached(widget_reference, graph_reference); //none-const
@@ -56,10 +62,11 @@ namespace nana
virtual void key_release(graph_reference, const arg_keyboard&); virtual void key_release(graph_reference, const arg_keyboard&);
virtual void shortkey(graph_reference, const arg_keyboard&); virtual void shortkey(graph_reference, const arg_keyboard&);
void _m_reset_overrided();
bool _m_overrided() const;
private: private:
bool overrided_{false}; void _m_reset_overrided();
bool _m_overrided(event_code) const;
private:
unsigned overrided_{ 0xFFFFFFFF };
}; };
namespace detail namespace detail
@@ -83,7 +90,7 @@ namespace nana
enum class method_state enum class method_state
{ {
unknown, pending,
overrided, overrided,
not_overrided not_overrided
}; };
@@ -127,23 +134,20 @@ namespace nana
template<typename Arg, typename Mfptr> template<typename Arg, typename Mfptr>
void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr) void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr)
{
if (realizer_)
{ {
const int pos = static_cast<int>(evt_code); const int pos = static_cast<int>(evt_code);
if (method_state::not_overrided != mth_state_[pos]) if (realizer_ && (method_state::not_overrided != mth_state_[pos]))
{ {
_m_bground_pre(); _m_bground_pre();
if (method_state::unknown == mth_state_[pos]) if (method_state::pending == mth_state_[pos])
{ {
realizer_->_m_reset_overrided();
(realizer_->*mfptr)(graphics, arg); (realizer_->*mfptr)(graphics, arg);
//Check realizer, when the window is closed in that event handler, the drawer will be //Check realizer, when the window is closed in that event handler, the drawer will be
//detached and realizer will be a nullptr //detached and realizer will be a nullptr
if(realizer_) if(realizer_)
mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided); mth_state_[pos] = (realizer_->_m_overrided(evt_code) ? method_state::overrided : method_state::not_overrided);
} }
else else
(realizer_->*mfptr)(graphics, arg); (realizer_->*mfptr)(graphics, arg);
@@ -155,7 +159,6 @@ namespace nana
} }
} }
} }
}
public: public:
nana::paint::graphics graphics; nana::paint::graphics graphics;
private: private:

View File

@@ -23,7 +23,7 @@ namespace nana{
return object; return object;
} }
std::size_t weight() const unsigned weight() const
{ {
return 2; return 2;
} }
@@ -55,22 +55,23 @@ namespace nana{
} }
} }
bool render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr)
{ {
bool rendered = false; bool copy_separately = true;
core_window_t * root_wd = wd->root_widget; std::vector<std::pair<rectangle, core_window_t*>> rd_set;
if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size())
{
auto root_wd = wd->root_widget;
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
if(nimbus.size()) auto focused = root_wd->other.attribute.root->focus;
{
core_window_t * focused = root_wd->other.attribute.root->focus; const unsigned pixels = weight();
native_window_type native = root_wd->root;
std::size_t pixels = weight();
auto graph = root_wd->root_graph; auto graph = root_wd->root_graph;
std::vector<core_window_t*> erase;
std::vector<std::pair<rectangle,core_window_t*>> rd_set;
nana::rectangle r; nana::rectangle r;
for(auto & action : nimbus) for(auto & action : nimbus)
{ {
@@ -80,11 +81,11 @@ namespace nana{
{ {
if (update_area) if (update_area)
::nana::overlap(*update_area, rectangle(r), r); ::nana::overlap(*update_area, rectangle(r), r);
rendered = true; copy_separately = false;
} }
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh))
{ {
rd_set.emplace_back(r, action.window); rd_set.emplace_back(r, action.window);
action.rendered = true; action.rendered = true;
@@ -93,30 +94,37 @@ namespace nana{
else if(action.rendered) else if(action.rendered)
{ {
action.rendered = false; action.rendered = false;
erase.push_back(action.window);
if (action.window == wd)
copy_separately = false;
::nana::rectangle erase_r(
action.window->pos_root.x - static_cast<int>(pixels),
action.window->pos_root.y - static_cast<int>(pixels),
static_cast<unsigned>(action.window->dimension.width + (pixels << 1)),
static_cast<unsigned>(action.window->dimension.height + (pixels << 1))
);
graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y);
}
} }
} }
//Erase if (copy_separately)
for(auto el : erase)
{ {
if(el == wd) rectangle vr;
rendered = true; if (window_layer::read_visual_rectangle(wd, vr))
{
r.x = el->pos_root.x - static_cast<int>(pixels); if (update_area)
r.y = el->pos_root.y - static_cast<int>(pixels); ::nana::overlap(*update_area, rectangle(vr), vr);
r.width = static_cast<unsigned>(el->dimension.width + (pixels << 1)); wd->root_graph->paste(wd->root, vr, vr.x, vr.y);
r.height = static_cast<unsigned>(el->dimension.height + (pixels << 1)); }
graph->paste(native, r, r.x, r.y);
} }
//Render //Render
for (auto & rd : rd_set) for (auto & rd : rd_set)
_m_render_edge_nimbus(rd.second, rd.first); _m_render_edge_nimbus(rd.second, rd.first);
} }
return rendered;
}
private: private:
static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd) static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd)
{ {
@@ -135,7 +143,7 @@ namespace nana{
if(overlap(r, wd->root_graph->size(), good_r)) if(overlap(r, wd->root_graph->size(), good_r))
{ {
if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
(good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height)) (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom()))
{ {
auto graph = wd->root_graph; auto graph = wd->root_graph;
nana::paint::pixel_buffer pixbuf(graph->handle(), r); nana::paint::pixel_buffer pixbuf(graph->handle(), r);

View File

@@ -109,7 +109,7 @@ namespace nana
if(real_visible_state_ != isshow) if(real_visible_state_ != isshow)
{ {
real_visible_state_ = isshow; real_visible_state_ = isshow;
native_interface::caret_visible(wd_->root, isshow); native_interface::caret_visible(wd_->root, isshow && wd_->displayed());
} }
} }
@@ -282,6 +282,11 @@ namespace nana
return true; return true;
} }
bool basic_window::displayed() const
{
return (visible && visible_parents());
}
bool basic_window::belong_to_lazy() const bool basic_window::belong_to_lazy() const
{ {
for (auto wd = this; wd; wd = wd->parent) for (auto wd = this; wd; wd = wd->parent)
@@ -292,6 +297,26 @@ namespace nana
return false; return false;
} }
const basic_window* get_child_caret(const basic_window* wd, bool this_is_a_child)
{
if (this_is_a_child && wd->together.caret)
return wd;
for (auto child : wd->children)
{
auto caret_wd = get_child_caret(child, true);
if (caret_wd)
return caret_wd;
}
return nullptr;
}
const basic_window * basic_window::child_caret() const
{
return get_child_caret(this, false);
}
bool basic_window::is_draw_through() const bool basic_window::is_draw_through() const
{ {
if (::nana::category::flags::root == this->other.category) if (::nana::category::flags::root == this->other.category)

View File

@@ -63,15 +63,16 @@ namespace nana
arg.window_handle = reinterpret_cast<window>(wd); arg.window_handle = reinterpret_cast<window>(wd);
if (emit(event_code::expose, wd, arg, false, get_thread_context())) if (emit(event_code::expose, wd, arg, false, get_thread_context()))
{ {
if (wd->together.caret) const core_window_t * caret_wd = (wd->together.caret ? wd : wd->child_caret());
if (caret_wd)
{ {
if (exposed) if (exposed)
{ {
if (wd->root_widget->other.attribute.root->focus == wd) if (wd->root_widget->other.attribute.root->focus == caret_wd)
wd->together.caret->visible(true); caret_wd->together.caret->visible(true);
} }
else else
wd->together.caret->visible(false); caret_wd->together.caret->visible(false);
} }
if (!exposed) if (!exposed)
@@ -102,7 +103,7 @@ namespace nana
arg.x = x; arg.x = x;
arg.y = y; arg.y = y;
if (emit(event_code::move, wd, arg, false, get_thread_context())) if (emit(event_code::move, wd, arg, false, get_thread_context()))
wd_manager.update(wd, true, true); wd_manager.update(wd, false, true);
} }
} }

View File

@@ -34,99 +34,99 @@ namespace nana
void drawer_trigger::resizing(graph_reference, const arg_resizing&) void drawer_trigger::resizing(graph_reference, const arg_resizing&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::resizing));
} }
void drawer_trigger::resized(graph_reference graph, const arg_resized&) void drawer_trigger::resized(graph_reference graph, const arg_resized&)
{ {
overrided_ = true; overrided_ |= (1 << static_cast<int>(event_code::resized));
this->refresh(graph); this->refresh(graph);
detail::bedrock::instance().thread_context_lazy_refresh(); detail::bedrock::instance().thread_context_lazy_refresh();
} }
void drawer_trigger::move(graph_reference, const arg_move&) void drawer_trigger::move(graph_reference, const arg_move&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::move));
} }
void drawer_trigger::click(graph_reference, const arg_mouse&) void drawer_trigger::click(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::click));
} }
void drawer_trigger::dbl_click(graph_reference, const arg_mouse&) void drawer_trigger::dbl_click(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::dbl_click));
} }
void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&) void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_enter));
} }
void drawer_trigger::mouse_move(graph_reference, const arg_mouse&) void drawer_trigger::mouse_move(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_move));
} }
void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&) void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_leave));
} }
void drawer_trigger::mouse_down(graph_reference, const arg_mouse&) void drawer_trigger::mouse_down(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_down));
} }
void drawer_trigger::mouse_up(graph_reference, const arg_mouse&) void drawer_trigger::mouse_up(graph_reference, const arg_mouse&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_up));
} }
void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&) void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_wheel));
} }
void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&) void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::mouse_drop));
} }
void drawer_trigger::focus(graph_reference, const arg_focus&) void drawer_trigger::focus(graph_reference, const arg_focus&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::focus));
} }
void drawer_trigger::key_press(graph_reference, const arg_keyboard&) void drawer_trigger::key_press(graph_reference, const arg_keyboard&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::key_press));
} }
void drawer_trigger::key_char(graph_reference, const arg_keyboard&) void drawer_trigger::key_char(graph_reference, const arg_keyboard&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::key_char));
} }
void drawer_trigger::key_release(graph_reference, const arg_keyboard&) void drawer_trigger::key_release(graph_reference, const arg_keyboard&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::key_release));
} }
void drawer_trigger::shortkey(graph_reference, const arg_keyboard&) void drawer_trigger::shortkey(graph_reference, const arg_keyboard&)
{ {
overrided_ = false; overrided_ &= ~(1 << static_cast<int>(event_code::shortkey));
} }
void drawer_trigger::_m_reset_overrided() void drawer_trigger::_m_reset_overrided()
{ {
overrided_ = true; overrided_ = 0xFFFFFFFF;
} }
bool drawer_trigger::_m_overrided() const bool drawer_trigger::_m_overrided(event_code evt_code) const
{ {
return overrided_; return 0 != (overrided_ & (1 << static_cast<int>(evt_code)));
} }
//end class drawer_trigger //end class drawer_trigger
@@ -244,8 +244,8 @@ namespace nana
{ {
if(wd) if(wd)
{ {
bedrock_type::core_window_t* iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd); auto iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus; auto caret_wd = iwd->root_widget->other.attribute.root->focus;
bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible())); bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible()));
@@ -262,16 +262,7 @@ namespace nana
#endif #endif
} }
if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) edge_nimbus_renderer_t::instance().render(iwd, forced, update_area);
{
rectangle vr;
if (bedrock_type::window_manager_t::window_layer::read_visual_rectangle(iwd, vr))
{
if (update_area)
::nana::overlap(*update_area, rectangle(vr), vr);
iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y);
}
}
if(owns_caret) if(owns_caret)
{ {
@@ -306,9 +297,10 @@ namespace nana
void drawer::attached(widget& wd, drawer_trigger& realizer) void drawer::attached(widget& wd, drawer_trigger& realizer)
{ {
for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i) for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i)
*i = method_state::unknown; *i = method_state::pending;
realizer_ = &realizer; realizer_ = &realizer;
realizer._m_reset_overrided();
realizer.attached(wd, graphics); realizer.attached(wd, graphics);
} }

View File

@@ -937,11 +937,10 @@ namespace detail
if(msgwnd->visible && (msgwnd->root_graph->empty() == false)) if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
{ {
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;
nana::detail::drawable_impl_type* drawer_impl = msgwnd->root_graph->handle(); //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
::XCopyArea(display, drawer_impl->pixmap, reinterpret_cast<Window>(native_window), drawer_impl->context, ::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height);
xevent.xexpose.x, xevent.xexpose.y, if (!update_area.empty())
xevent.xexpose.width, xevent.xexpose.height, msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
xevent.xexpose.x, xevent.xexpose.y);
} }
break; break;
case KeyPress: case KeyPress:
@@ -1149,6 +1148,8 @@ namespace detail
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context); brock.emit(event_code::key_release, msgwnd, arg, true, &context);
} }
if (context.platform.keychar < keyboard::os_arrow_left || keyboard::os_arrow_down < wParam)
brock.delay_restore(2); //Restores while key release brock.delay_restore(2); //Restores while key release
} }
else else

View File

@@ -363,7 +363,7 @@ namespace detail
void bedrock::pump_event(window modal_window, bool is_modal) void bedrock::pump_event(window modal_window, bool is_modal)
{ {
const unsigned tid = ::GetCurrentThreadId(); const unsigned tid = ::GetCurrentThreadId();
thread_context * context = this->open_thread_context(tid); auto context = this->open_thread_context(tid);
if(0 == context->window_count) if(0 == context->window_count)
{ {
//test if there is not a window //test if there is not a window
@@ -1310,13 +1310,11 @@ namespace detail
::PAINTSTRUCT ps; ::PAINTSTRUCT ps;
::HDC dc = ::BeginPaint(root_window, &ps); ::HDC dc = ::BeginPaint(root_window, &ps);
if((ps.rcPaint.left != ps.rcPaint.right) && (ps.rcPaint.bottom != ps.rcPaint.top)) //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
{ ::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
::BitBlt(dc, if (!update_area.empty())
ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
reinterpret_cast<HDC>(msgwnd->root_graph->handle()->context),
ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
}
::EndPaint(root_window, &ps); ::EndPaint(root_window, &ps);
} }
break; break;
@@ -1474,6 +1472,9 @@ namespace detail
else else
brock.set_keyboard_shortkey(false); brock.set_keyboard_shortkey(false);
//Do delay restore if key is not arrow_left/right/up/down, otherwise
//A menubar will be restored if the item is empty(not have a menu item)
if (wParam < 37 || 40 < wParam)
brock.delay_restore(2); //Restores while key release brock.delay_restore(2); //Restores while key release
break; break;
case WM_CLOSE: case WM_CLOSE:

View File

@@ -59,7 +59,6 @@ namespace nana
if (wd->parent) if (wd->parent)
{ {
std::vector<wd_rectangle> blocks; std::vector<wd_rectangle> blocks;
blocks.reserve(10);
if (read_overlaps(wd, vr, blocks)) if (read_overlaps(wd, vr, blocks))
{ {
nana::point p_src; nana::point p_src;
@@ -99,7 +98,7 @@ namespace nana
// The result is a rectangle that is a visible area for its ancesters. // The result is a rectangle that is a visible area for its ancesters.
bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual) bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual)
{ {
if (false == wd->visible) return false; if (! wd->displayed()) return false;
visual = rectangle{ wd->pos_root, wd->dimension }; visual = rectangle{ wd->pos_root, wd->dimension };
@@ -354,7 +353,7 @@ namespace nana
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows) for (auto wd : data_sect.effects_bground_windows)
{ {
if (wd == sigwd || !wd->visible || !wd->visible_parents() || if (wd == sigwd || !wd->displayed() ||
(false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd))) (false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd)))
continue; continue;

View File

@@ -698,7 +698,7 @@ namespace detail
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<decltype(mutex_)> lock(mutex_);
if (impl_->wd_register.available(wd) == false) return false; if (impl_->wd_register.available(wd) == false) return false;
if (wd->visible && wd->visible_parents()) if (wd->displayed())
{ {
if(forced || (false == wd->belong_to_lazy())) if(forced || (false == wd->belong_to_lazy()))
{ {
@@ -722,7 +722,7 @@ namespace detail
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<decltype(mutex_)> lock(mutex_);
//It's not worthy to redraw if visible is false //It's not worthy to redraw if visible is false
if (impl_->wd_register.available(wd) && wd->visible && wd->visible_parents()) if (impl_->wd_register.available(wd) && wd->displayed())
window_layer::paint(wd, true, true); window_layer::paint(wd, true, true);
} }
@@ -1060,7 +1060,7 @@ namespace detail
bool precondition = false; bool precondition = false;
for (auto & tab_wd : tabs) for (auto & tab_wd : tabs)
{ {
if (tab_wd->visible) if (tab_wd->displayed())
{ {
precondition = true; precondition = true;
break; break;
@@ -1073,7 +1073,7 @@ namespace detail
while (new_stop && (wd != new_stop)) while (new_stop && (wd != new_stop))
{ {
if (new_stop->flags.enabled && new_stop->visible) if (new_stop->flags.enabled && new_stop->displayed())
return new_stop; return new_stop;
new_stop = get_tabstop(new_stop, forward); new_stop = get_tabstop(new_stop, forward);

View File

@@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase
void trigger::key_char(graph_reference, const arg_keyboard& arg) void trigger::key_char(graph_reference, const arg_keyboard& arg)
{ {
if(arg.key == static_cast<char_t>(keyboard::enter)) if (static_cast<char_t>(keyboard::enter) == arg.key || static_cast<char_t>(keyboard::space) == arg.key)
emit_click(); emit_click();
} }

View File

@@ -3512,6 +3512,7 @@ namespace nana
m.flags.checked = ck; m.flags.checked = ck;
arg_listbox arg{*this, ck}; arg_listbox arg{*this, ck};
ess_->lister.wd_ptr()->events().checked.emit(arg); ess_->lister.wd_ptr()->events().checked.emit(arg);
ess_->update();
} }
return *this; return *this;
} }
@@ -3539,6 +3540,7 @@ namespace nana
else if (ess_->lister.last_selected_abs == pos_) else if (ess_->lister.last_selected_abs == pos_)
ess_->lister.last_selected_abs.set_both(npos); ess_->lister.last_selected_abs.set_both(npos);
ess_->update();
return *this; return *this;
} }

View File

@@ -114,7 +114,7 @@ namespace nana
{ {
if(at.item_state == state::active) if(at.item_state == state::active)
{ {
graph.rectangle(r, false, {0xa8, 0xd8, 0xeb}); graph.rectangle(r, false, static_cast<color_rgb>(0xa8d8eb));
nana::point points[4] = { nana::point points[4] = {
nana::point(r.x, r.y), nana::point(r.x, r.y),
nana::point(r.x + r.width - 1, r.y), nana::point(r.x + r.width - 1, r.y),
@@ -200,8 +200,9 @@ namespace nana
void checked(std::size_t index, bool check) void checked(std::size_t index, bool check)
{ {
if(root_.items.size() > index) if (root_.items.size() <= index)
{ return;
item_type & m = root_.items[index]; item_type & m = root_.items[index];
if(check && (checks::option == m.style)) if(check && (checks::option == m.style))
{ {
@@ -229,7 +230,6 @@ namespace nana
} }
m.flags.checked = check; m.flags.checked = check;
} }
}
menu_type& data() menu_type& data()
{ {
@@ -304,7 +304,7 @@ namespace nana
: public drawer_trigger : public drawer_trigger
{ {
public: public:
typedef menu_item_type::item_proxy item_proxy; using item_proxy = menu_item_type::item_proxy;
renderer_interface * renderer; renderer_interface * renderer;
@@ -330,12 +330,12 @@ namespace nana
detail_.monitor_pos = API::cursor_position(); detail_.monitor_pos = API::cursor_position();
} }
void mouse_move(graph_reference, const arg_mouse& arg) void mouse_move(graph_reference graph, const arg_mouse& arg)
{ {
state_.nullify_mouse = false; state_.nullify_mouse = false;
if(track_mouse(arg.pos.x, arg.pos.y)) if(track_mouse(arg.pos))
{ {
draw(); refresh(graph);
API::lazy_refresh(); API::lazy_refresh();
} }
} }
@@ -350,9 +350,70 @@ namespace nana
state_.nullify_mouse = false; state_.nullify_mouse = false;
} }
void refresh(graph_reference) void refresh(graph_reference graph)
{ {
draw(); if (nullptr == menu_) return;
_m_adjust_window_size();
renderer->background(graph, *widget_);
const unsigned item_h_px = _m_item_height();
const unsigned image_px = item_h_px - 2;
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph.text_extent_size(STR("jh({[")).height) / 2;
std::size_t pos = 0;
for (auto & m : menu_->items)
{
if (m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y });
item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if (m.image.empty() == false)
renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, m.image);
renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if (hotkey)
{
m.hotkey = hotkey;
if (m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph.text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if (m.sub_menu)
renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
}
} }
std::size_t active() const std::size_t active() const
@@ -411,18 +472,18 @@ namespace nana
state_.active = pos; state_.active = pos;
state_.sub_window = false; state_.sub_window = false;
draw(); refresh(*graph_);
return true; return true;
} }
return false; return false;
} }
bool track_mouse(int x, int y) bool track_mouse(const ::nana::point& pos)
{ {
if(state_.nullify_mouse == false) if (!state_.nullify_mouse)
{ {
std::size_t index = _m_get_index_by_pos(x, y); std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
if (index != state_.active) if (index != state_.active)
{ {
if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window) if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
@@ -433,6 +494,7 @@ namespace nana
return true; return true;
} }
} }
return false; return false;
} }
@@ -451,29 +513,35 @@ namespace nana
state_.sub_window = subw; state_.sub_window = subw;
} }
menu_type* retrive_sub_menu(nana::point& pos, std::size_t interval) const menu_type* get_sub(nana::point& pos, unsigned long& tmstamp) const
{ {
if(state_.active != npos && (nana::system::timestamp() - state_.active_timestamp >= interval)) if (npos == state_.active)
return nullptr;
auto sub = menu_->items.at(state_.active).sub_menu;
if (sub)
{ {
pos.x = graph_->width() - 2; pos.x = static_cast<int>(graph_->width()) - 2;
pos.y = 2; pos.y = 2;
std::size_t index = 0; auto index = state_.active;
for (auto & m : menu_->items) for (auto & m : menu_->items)
{ {
if(false == m.flags.splitter) if (m.flags.splitter)
{ {
if(index == state_.active) pos.y += 2;
continue;
}
if (0 == index)
break; break;
pos.y += _m_item_height() + 1; pos.y += _m_item_height() + 1;
--index;
} }
else
pos.y += 2;
++index; tmstamp = state_.active_timestamp;
} return sub;
return (menu_->items.at(state_.active).sub_menu);
} }
return nullptr; return nullptr;
} }
@@ -498,8 +566,7 @@ namespace nana
state_.active = index; state_.active = index;
state_.active_timestamp = nana::system::timestamp(); state_.active_timestamp = nana::system::timestamp();
draw(); API::refresh_window(*widget_);
API::update_window(*widget_);
return 2; return 2;
} }
else if(m.flags.enabled) else if(m.flags.enabled)
@@ -514,72 +581,6 @@ namespace nana
} }
return 0; return 0;
} }
void draw() const
{
if(nullptr == menu_) return;
_m_adjust_window_size();
renderer->background(*graph_, *widget_);
const unsigned item_h_px = _m_item_height();
const unsigned image_px = item_h_px - 2;
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
std::size_t pos = 0;
for(auto & m : menu_->items)
{
if(m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
}
}
private: private:
static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m) static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m)
{ {
@@ -685,9 +686,9 @@ namespace nana
struct state struct state
{ {
std::size_t active; std::size_t active;
unsigned long active_timestamp; unsigned active_timestamp;
unsigned long sub_window: 1; bool sub_window: 1;
unsigned long nullify_mouse: 1; bool nullify_mouse: 1;
}state_; }state_;
struct widget_detail struct widget_detail
@@ -722,7 +723,19 @@ namespace nana
submenu_.child = submenu_.parent = nullptr; submenu_.child = submenu_.parent = nullptr;
submenu_.object = nullptr; submenu_.object = nullptr;
_m_make_mouse_event(); state_.mouse_pos = API::cursor_position();
events().mouse_move.connect_unignorable([this]{
nana::point pos = API::cursor_position();
if (pos != state_.mouse_pos)
{
menu_window * root = this;
while (root->submenu_.parent)
root = root->submenu_.parent;
root->state_.auto_popup_submenu = true;
state_.mouse_pos = pos;
}
});
} }
void popup(menu_type& menu, bool owner_menubar) void popup(menu_type& menu, bool owner_menubar)
@@ -749,13 +762,19 @@ namespace nana
_m_key_down(arg); _m_key_down(arg);
}); });
events().mouse_up.connect_unignorable([this]{ events().mouse_down.connect_unignorable([this](const arg_mouse& arg)
{
this->_m_open_sub(0); //Try to open submenu immediately
});
events().mouse_up.connect_unignorable([this](const arg_mouse& arg){
if (arg.left_button)
pick(); pick();
}); });
timer_.interval(100); timer_.interval(100);
timer_.elapse([this]{ timer_.elapse([this]{
this->_m_check_repeatly(); this->_m_open_sub(500); //Try to open submenu
}); });
timer_.start(); timer_.start();
@@ -801,29 +820,27 @@ namespace nana
bool submenu(bool enter) bool submenu(bool enter)
{ {
menu_window * object = this; menu_window * menu_wd = this;
while (object->submenu_.child) while (menu_wd->submenu_.child)
object = object->submenu_.child; menu_wd = menu_wd->submenu_.child;
state_.auto_popup_submenu = false; state_.auto_popup_submenu = false;
if (enter) if (!enter)
{ {
if (object->submenu_.parent) if (menu_wd->submenu_.parent)
{ {
auto & sub = object->submenu_.parent->submenu_; auto & sub = menu_wd->submenu_.parent->submenu_;
sub.child = nullptr; sub.child = nullptr;
sub.object = nullptr; sub.object = nullptr;
object->close(); menu_wd->close();
return true; return true;
} }
return false; return false;
} }
nana::point pos; return menu_wd->_m_manipulate_sub(0, true);
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
return object->_m_show_submenu(sbm, pos, true);
} }
int send_shortkey(nana::char_t key) int send_shortkey(nana::char_t key)
@@ -969,62 +986,50 @@ namespace nana
} }
} }
void _m_make_mouse_event() bool _m_manipulate_sub(unsigned long delay_ms, bool forced)
{ {
state_.mouse_pos = API::cursor_position(); auto & drawer = get_drawer_trigger();
events().mouse_move.connect_unignorable([this]{ ::nana::point pos;
_m_mouse_event(); unsigned long tmstamp;
});
}
void _m_mouse_event() auto menu_ptr = drawer.get_sub(pos, tmstamp);
{
nana::point pos = API::cursor_position();
if(pos != state_.mouse_pos)
{
menu_window * root = this;
while(root->submenu_.parent)
root = root->submenu_.parent;
root->state_.auto_popup_submenu = true;
state_.mouse_pos = pos; if (menu_ptr == submenu_.object)
} return false;
}
bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced) if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms))
return false;
if (submenu_.object && (menu_ptr != submenu_.object))
{ {
auto & mdtrigger = get_drawer_trigger(); drawer.set_sub_window(false);
if(submenu_.object && (sbm != submenu_.object))
{
mdtrigger.set_sub_window(false);
submenu_.child->close(); submenu_.child->close();
submenu_.child = nullptr; submenu_.child = nullptr;
submenu_.object = nullptr; submenu_.object = nullptr;
} }
if(sbm) if (menu_ptr)
{ {
menu_window * root = this; menu_window * root = this;
while (root->submenu_.parent) while (root->submenu_.parent)
root = root->submenu_.parent; root = root->submenu_.parent;
if((submenu_.object == nullptr) && sbm && (forced || root->state_.auto_popup_submenu)) if ((submenu_.object == nullptr) && menu_ptr && (forced || root->state_.auto_popup_submenu))
{ {
sbm->item_pixels = mdtrigger.data()->item_pixels; menu_ptr->item_pixels = drawer.data()->item_pixels;
sbm->gaps = mdtrigger.data()->gaps; menu_ptr->gaps = drawer.data()->gaps;
pos.x += sbm->gaps.x; pos += menu_ptr->gaps;
pos.y += sbm->gaps.y;
menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, mdtrigger.renderer); menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.renderer);
mwnd.state_.self_submenu = true; mwnd.state_.self_submenu = true;
submenu_.child = &mwnd; submenu_.child = &mwnd;
submenu_.child->submenu_.parent = this; submenu_.child->submenu_.parent = this;
submenu_.object = sbm; submenu_.object = menu_ptr;
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none); API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
mwnd.popup(*sbm, state_.owner_menubar); mwnd.popup(*menu_ptr, state_.owner_menubar);
mdtrigger.set_sub_window(true); drawer.set_sub_window(true);
if (forced) if (forced)
mwnd.goto_next(true); mwnd.goto_next(true);
@@ -1034,17 +1039,16 @@ namespace nana
return false; return false;
} }
void _m_check_repeatly() void _m_open_sub(unsigned delay_ms) //check_repeatly
{ {
if(state_.auto_popup_submenu) if(state_.auto_popup_submenu)
{ {
nana::point pos = API::cursor_position(); auto pos = API::cursor_position();
drawer_type& drawer = get_drawer_trigger();
API::calc_window_point(handle(), pos); API::calc_window_point(handle(), pos);
drawer.track_mouse(pos.x, pos.y); get_drawer_trigger().track_mouse(pos);
menu_type* sbm = drawer.retrive_sub_menu(pos, 500);
_m_show_submenu(sbm, pos, false); _m_manipulate_sub(delay_ms, false);
} }
} }
private: private: