Merge remote-tracking branch 'nana_jinhao/hotfixes-1.0.2' into hotfixes-1.0.2
This commit is contained in:
commit
6f101f73b4
@ -84,6 +84,7 @@ namespace nana
|
||||
end_of_medium = 0x19, //Ctrl+Y
|
||||
substitute = 0x1A, //Ctrl+Z
|
||||
escape = 0x1B,
|
||||
space = 0x20, //Space
|
||||
|
||||
//The following names are intuitive name of ASCII control codes
|
||||
select_all = start_of_headline,
|
||||
|
@ -118,9 +118,11 @@ namespace detail
|
||||
|
||||
bool is_ancestor_of(const basic_window* wd) const;
|
||||
bool visible_parents() const;
|
||||
bool displayed() 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:
|
||||
//Override event_holder
|
||||
bool set_events(const std::shared_ptr<general_events>&) override;
|
||||
|
@ -23,12 +23,18 @@ namespace nana
|
||||
{
|
||||
class widget;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class drawer;
|
||||
}
|
||||
|
||||
class drawer_trigger
|
||||
: ::nana::noncopyable, ::nana::nonmovable
|
||||
{
|
||||
friend class detail::drawer;
|
||||
public:
|
||||
typedef widget& widget_reference;
|
||||
typedef paint::graphics& graph_reference;
|
||||
using widget_reference = widget&;
|
||||
using graph_reference = paint::graphics&;
|
||||
|
||||
virtual ~drawer_trigger();
|
||||
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 shortkey(graph_reference, const arg_keyboard&);
|
||||
|
||||
void _m_reset_overrided();
|
||||
bool _m_overrided() const;
|
||||
private:
|
||||
bool overrided_{false};
|
||||
void _m_reset_overrided();
|
||||
bool _m_overrided(event_code) const;
|
||||
private:
|
||||
unsigned overrided_{ 0xFFFFFFFF };
|
||||
};
|
||||
|
||||
namespace detail
|
||||
@ -83,7 +90,7 @@ namespace nana
|
||||
|
||||
enum class method_state
|
||||
{
|
||||
unknown,
|
||||
pending,
|
||||
overrided,
|
||||
not_overrided
|
||||
};
|
||||
@ -128,31 +135,27 @@ namespace nana
|
||||
template<typename Arg, typename Mfptr>
|
||||
void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr)
|
||||
{
|
||||
if (realizer_)
|
||||
const int pos = static_cast<int>(evt_code);
|
||||
if (realizer_ && (method_state::not_overrided != mth_state_[pos]))
|
||||
{
|
||||
const int pos = static_cast<int>(evt_code);
|
||||
if (method_state::not_overrided != mth_state_[pos])
|
||||
_m_bground_pre();
|
||||
|
||||
if (method_state::pending == mth_state_[pos])
|
||||
{
|
||||
_m_bground_pre();
|
||||
(realizer_->*mfptr)(graphics, arg);
|
||||
|
||||
//Check realizer, when the window is closed in that event handler, the drawer will be
|
||||
//detached and realizer will be a nullptr
|
||||
if(realizer_)
|
||||
mth_state_[pos] = (realizer_->_m_overrided(evt_code) ? method_state::overrided : method_state::not_overrided);
|
||||
}
|
||||
else
|
||||
(realizer_->*mfptr)(graphics, arg);
|
||||
|
||||
if (method_state::unknown == mth_state_[pos])
|
||||
{
|
||||
realizer_->_m_reset_overrided();
|
||||
(realizer_->*mfptr)(graphics, arg);
|
||||
|
||||
//Check realizer, when the window is closed in that event handler, the drawer will be
|
||||
//detached and realizer will be a nullptr
|
||||
if(realizer_)
|
||||
mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided);
|
||||
}
|
||||
else
|
||||
(realizer_->*mfptr)(graphics, arg);
|
||||
|
||||
if (_m_lazy_decleared())
|
||||
{
|
||||
_m_draw_dynamic_drawing_object();
|
||||
_m_bground_end();
|
||||
}
|
||||
if (_m_lazy_decleared())
|
||||
{
|
||||
_m_draw_dynamic_drawing_object();
|
||||
_m_bground_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace nana{
|
||||
return object;
|
||||
}
|
||||
|
||||
std::size_t weight() const
|
||||
unsigned weight() const
|
||||
{
|
||||
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;
|
||||
core_window_t * root_wd = wd->root_widget;
|
||||
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
|
||||
bool copy_separately = true;
|
||||
std::vector<std::pair<rectangle, core_window_t*>> rd_set;
|
||||
|
||||
if(nimbus.size())
|
||||
if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size())
|
||||
{
|
||||
core_window_t * focused = root_wd->other.attribute.root->focus;
|
||||
native_window_type native = root_wd->root;
|
||||
std::size_t pixels = weight();
|
||||
auto root_wd = wd->root_widget;
|
||||
|
||||
auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus;
|
||||
|
||||
auto focused = root_wd->other.attribute.root->focus;
|
||||
|
||||
const unsigned pixels = weight();
|
||||
|
||||
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;
|
||||
for(auto & action : nimbus)
|
||||
{
|
||||
@ -80,11 +81,11 @@ namespace nana{
|
||||
{
|
||||
if (update_area)
|
||||
::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.
|
||||
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);
|
||||
action.rendered = true;
|
||||
@ -93,29 +94,36 @@ namespace nana{
|
||||
else if(action.rendered)
|
||||
{
|
||||
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
|
||||
for(auto el : erase)
|
||||
{
|
||||
if(el == wd)
|
||||
rendered = true;
|
||||
|
||||
r.x = el->pos_root.x - static_cast<int>(pixels);
|
||||
r.y = el->pos_root.y - static_cast<int>(pixels);
|
||||
r.width = static_cast<unsigned>(el->dimension.width + (pixels << 1));
|
||||
r.height = static_cast<unsigned>(el->dimension.height + (pixels << 1));
|
||||
|
||||
graph->paste(native, r, r.x, r.y);
|
||||
}
|
||||
|
||||
//Render
|
||||
for (auto & rd : rd_set)
|
||||
_m_render_edge_nimbus(rd.second, rd.first);
|
||||
}
|
||||
return rendered;
|
||||
|
||||
if (copy_separately)
|
||||
{
|
||||
rectangle vr;
|
||||
if (window_layer::read_visual_rectangle(wd, vr))
|
||||
{
|
||||
if (update_area)
|
||||
::nana::overlap(*update_area, rectangle(vr), vr);
|
||||
wd->root_graph->paste(wd->root, vr, vr.x, vr.y);
|
||||
}
|
||||
}
|
||||
|
||||
//Render
|
||||
for (auto & rd : rd_set)
|
||||
_m_render_edge_nimbus(rd.second, rd.first);
|
||||
}
|
||||
private:
|
||||
static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd)
|
||||
@ -134,8 +142,8 @@ namespace nana{
|
||||
nana::rectangle 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) ||
|
||||
(good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height))
|
||||
if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) ||
|
||||
(good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom()))
|
||||
{
|
||||
auto graph = wd->root_graph;
|
||||
nana::paint::pixel_buffer pixbuf(graph->handle(), r);
|
||||
|
@ -109,7 +109,7 @@ namespace nana
|
||||
if(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;
|
||||
}
|
||||
|
||||
bool basic_window::displayed() const
|
||||
{
|
||||
return (visible && visible_parents());
|
||||
}
|
||||
|
||||
bool basic_window::belong_to_lazy() const
|
||||
{
|
||||
for (auto wd = this; wd; wd = wd->parent)
|
||||
@ -292,6 +297,26 @@ namespace nana
|
||||
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
|
||||
{
|
||||
if (::nana::category::flags::root == this->other.category)
|
||||
|
@ -63,15 +63,16 @@ namespace nana
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
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 (wd->root_widget->other.attribute.root->focus == wd)
|
||||
wd->together.caret->visible(true);
|
||||
if (wd->root_widget->other.attribute.root->focus == caret_wd)
|
||||
caret_wd->together.caret->visible(true);
|
||||
}
|
||||
else
|
||||
wd->together.caret->visible(false);
|
||||
caret_wd->together.caret->visible(false);
|
||||
}
|
||||
|
||||
if (!exposed)
|
||||
@ -102,7 +103,7 @@ namespace nana
|
||||
arg.x = x;
|
||||
arg.y = y;
|
||||
if (emit(event_code::move, wd, arg, false, get_thread_context()))
|
||||
wd_manager.update(wd, true, true);
|
||||
wd_manager.update(wd, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,99 +34,99 @@ namespace nana
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = true;
|
||||
overrided_ |= (1 << static_cast<int>(event_code::resized));
|
||||
this->refresh(graph);
|
||||
detail::bedrock::instance().thread_context_lazy_refresh();
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::click));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_enter));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_leave));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_up));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::mouse_drop));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::key_press));
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
overrided_ = false;
|
||||
overrided_ &= ~(1 << static_cast<int>(event_code::key_release));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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
|
||||
@ -244,8 +244,8 @@ namespace nana
|
||||
{
|
||||
if(wd)
|
||||
{
|
||||
bedrock_type::core_window_t* iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
|
||||
bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus;
|
||||
auto iwd = reinterpret_cast<bedrock_type::core_window_t*>(wd);
|
||||
auto caret_wd = iwd->root_widget->other.attribute.root->focus;
|
||||
|
||||
bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible()));
|
||||
|
||||
@ -262,16 +262,7 @@ namespace nana
|
||||
#endif
|
||||
}
|
||||
|
||||
if (false == 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);
|
||||
}
|
||||
}
|
||||
edge_nimbus_renderer_t::instance().render(iwd, forced, update_area);
|
||||
|
||||
if(owns_caret)
|
||||
{
|
||||
@ -306,9 +297,10 @@ namespace nana
|
||||
void drawer::attached(widget& wd, drawer_trigger& realizer)
|
||||
{
|
||||
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._m_reset_overrided();
|
||||
realizer.attached(wd, graphics);
|
||||
}
|
||||
|
||||
|
@ -937,11 +937,10 @@ namespace detail
|
||||
if(msgwnd->visible && (msgwnd->root_graph->empty() == false))
|
||||
{
|
||||
nana::detail::platform_scope_guard psg;
|
||||
nana::detail::drawable_impl_type* drawer_impl = msgwnd->root_graph->handle();
|
||||
::XCopyArea(display, drawer_impl->pixmap, reinterpret_cast<Window>(native_window), drawer_impl->context,
|
||||
xevent.xexpose.x, xevent.xexpose.y,
|
||||
xevent.xexpose.width, xevent.xexpose.height,
|
||||
xevent.xexpose.x, xevent.xexpose.y);
|
||||
//Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed.
|
||||
::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height);
|
||||
if (!update_area.empty())
|
||||
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
@ -1149,7 +1148,9 @@ namespace detail
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||
}
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
|
||||
if (context.platform.keychar < keyboard::os_arrow_left || keyboard::os_arrow_down < wParam)
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -363,7 +363,7 @@ namespace detail
|
||||
void bedrock::pump_event(window modal_window, bool is_modal)
|
||||
{
|
||||
const unsigned tid = ::GetCurrentThreadId();
|
||||
thread_context * context = this->open_thread_context(tid);
|
||||
auto context = this->open_thread_context(tid);
|
||||
if(0 == context->window_count)
|
||||
{
|
||||
//test if there is not a window
|
||||
@ -1310,13 +1310,11 @@ namespace detail
|
||||
::PAINTSTRUCT ps;
|
||||
::HDC dc = ::BeginPaint(root_window, &ps);
|
||||
|
||||
if((ps.rcPaint.left != ps.rcPaint.right) && (ps.rcPaint.bottom != ps.rcPaint.top))
|
||||
{
|
||||
::BitBlt(dc,
|
||||
ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
|
||||
reinterpret_cast<HDC>(msgwnd->root_graph->handle()->context),
|
||||
ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
|
||||
}
|
||||
//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);
|
||||
if (!update_area.empty())
|
||||
msgwnd->drawer.map(reinterpret_cast<window>(msgwnd), true, &update_area);
|
||||
|
||||
::EndPaint(root_window, &ps);
|
||||
}
|
||||
break;
|
||||
@ -1474,7 +1472,10 @@ namespace detail
|
||||
else
|
||||
brock.set_keyboard_shortkey(false);
|
||||
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
//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
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
{
|
||||
|
@ -59,7 +59,6 @@ namespace nana
|
||||
if (wd->parent)
|
||||
{
|
||||
std::vector<wd_rectangle> blocks;
|
||||
blocks.reserve(10);
|
||||
if (read_overlaps(wd, vr, blocks))
|
||||
{
|
||||
nana::point p_src;
|
||||
@ -99,7 +98,7 @@ namespace nana
|
||||
// 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)
|
||||
{
|
||||
if (false == wd->visible) return false;
|
||||
if (! wd->displayed()) return false;
|
||||
|
||||
visual = rectangle{ wd->pos_root, wd->dimension };
|
||||
|
||||
@ -354,7 +353,7 @@ namespace nana
|
||||
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
|
||||
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)))
|
||||
continue;
|
||||
|
||||
|
@ -698,7 +698,7 @@ namespace detail
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
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()))
|
||||
{
|
||||
@ -722,7 +722,7 @@ namespace detail
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
@ -1060,7 +1060,7 @@ namespace detail
|
||||
bool precondition = false;
|
||||
for (auto & tab_wd : tabs)
|
||||
{
|
||||
if (tab_wd->visible)
|
||||
if (tab_wd->displayed())
|
||||
{
|
||||
precondition = true;
|
||||
break;
|
||||
@ -1073,7 +1073,7 @@ namespace detail
|
||||
|
||||
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;
|
||||
|
||||
new_stop = get_tabstop(new_stop, forward);
|
||||
|
@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -3512,6 +3512,7 @@ namespace nana
|
||||
m.flags.checked = ck;
|
||||
arg_listbox arg{*this, ck};
|
||||
ess_->lister.wd_ptr()->events().checked.emit(arg);
|
||||
ess_->update();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -3539,6 +3540,7 @@ namespace nana
|
||||
else if (ess_->lister.last_selected_abs == pos_)
|
||||
ess_->lister.last_selected_abs.set_both(npos);
|
||||
|
||||
ess_->update();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ namespace nana
|
||||
{
|
||||
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(r.x, r.y),
|
||||
nana::point(r.x + r.width - 1, r.y),
|
||||
@ -200,35 +200,35 @@ namespace nana
|
||||
|
||||
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];
|
||||
if(check && (checks::option == m.style))
|
||||
{
|
||||
item_type & m = root_.items[index];
|
||||
if(check && (checks::option == m.style))
|
||||
if(index)
|
||||
{
|
||||
if(index)
|
||||
std::size_t i = index;
|
||||
do
|
||||
{
|
||||
std::size_t i = index;
|
||||
do
|
||||
{
|
||||
item_type& el = root_.items[--i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}while(i);
|
||||
}
|
||||
|
||||
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
|
||||
{
|
||||
item_type & el = root_.items[i];
|
||||
item_type& el = root_.items[--i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}
|
||||
}while(i);
|
||||
}
|
||||
|
||||
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
|
||||
{
|
||||
item_type & el = root_.items[i];
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}
|
||||
m.flags.checked = check;
|
||||
}
|
||||
m.flags.checked = check;
|
||||
}
|
||||
|
||||
menu_type& data()
|
||||
@ -304,7 +304,7 @@ namespace nana
|
||||
: public drawer_trigger
|
||||
{
|
||||
public:
|
||||
typedef menu_item_type::item_proxy item_proxy;
|
||||
using item_proxy = menu_item_type::item_proxy;
|
||||
|
||||
renderer_interface * renderer;
|
||||
|
||||
@ -330,12 +330,12 @@ namespace nana
|
||||
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;
|
||||
if(track_mouse(arg.pos.x, arg.pos.y))
|
||||
if(track_mouse(arg.pos))
|
||||
{
|
||||
draw();
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
}
|
||||
@ -350,9 +350,70 @@ namespace nana
|
||||
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
|
||||
@ -411,21 +472,21 @@ namespace nana
|
||||
state_.active = pos;
|
||||
state_.sub_window = false;
|
||||
|
||||
draw();
|
||||
refresh(*graph_);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
if(index != state_.active)
|
||||
std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
|
||||
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)
|
||||
return false;
|
||||
|
||||
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index;
|
||||
@ -433,6 +494,7 @@ namespace nana
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -451,29 +513,35 @@ namespace nana
|
||||
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;
|
||||
|
||||
std::size_t index = 0;
|
||||
for(auto & m : menu_->items)
|
||||
auto index = state_.active;
|
||||
for (auto & m : menu_->items)
|
||||
{
|
||||
if(false == m.flags.splitter)
|
||||
if (m.flags.splitter)
|
||||
{
|
||||
if(index == state_.active)
|
||||
break;
|
||||
|
||||
pos.y += _m_item_height() + 1;
|
||||
}
|
||||
else
|
||||
pos.y += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
++index;
|
||||
if (0 == index)
|
||||
break;
|
||||
|
||||
pos.y += _m_item_height() + 1;
|
||||
--index;
|
||||
}
|
||||
return (menu_->items.at(state_.active).sub_menu);
|
||||
|
||||
tmstamp = state_.active_timestamp;
|
||||
return sub;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -498,8 +566,7 @@ namespace nana
|
||||
state_.active = index;
|
||||
state_.active_timestamp = nana::system::timestamp();
|
||||
|
||||
draw();
|
||||
API::update_window(*widget_);
|
||||
API::refresh_window(*widget_);
|
||||
return 2;
|
||||
}
|
||||
else if(m.flags.enabled)
|
||||
@ -514,72 +581,6 @@ namespace nana
|
||||
}
|
||||
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:
|
||||
static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m)
|
||||
{
|
||||
@ -684,10 +685,10 @@ namespace nana
|
||||
|
||||
struct state
|
||||
{
|
||||
std::size_t active;
|
||||
unsigned long active_timestamp;
|
||||
unsigned long sub_window: 1;
|
||||
unsigned long nullify_mouse: 1;
|
||||
std::size_t active;
|
||||
unsigned active_timestamp;
|
||||
bool sub_window: 1;
|
||||
bool nullify_mouse: 1;
|
||||
}state_;
|
||||
|
||||
struct widget_detail
|
||||
@ -722,7 +723,19 @@ namespace nana
|
||||
submenu_.child = submenu_.parent = 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)
|
||||
@ -749,13 +762,19 @@ namespace nana
|
||||
_m_key_down(arg);
|
||||
});
|
||||
|
||||
events().mouse_up.connect_unignorable([this]{
|
||||
pick();
|
||||
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();
|
||||
});
|
||||
|
||||
timer_.interval(100);
|
||||
timer_.elapse([this]{
|
||||
this->_m_check_repeatly();
|
||||
this->_m_open_sub(500); //Try to open submenu
|
||||
});
|
||||
timer_.start();
|
||||
|
||||
@ -801,29 +820,27 @@ namespace nana
|
||||
|
||||
bool submenu(bool enter)
|
||||
{
|
||||
menu_window * object = this;
|
||||
while (object->submenu_.child)
|
||||
object = object->submenu_.child;
|
||||
menu_window * menu_wd = this;
|
||||
while (menu_wd->submenu_.child)
|
||||
menu_wd = menu_wd->submenu_.child;
|
||||
|
||||
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.object = nullptr;
|
||||
|
||||
object->close();
|
||||
menu_wd->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nana::point pos;
|
||||
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
|
||||
return object->_m_show_submenu(sbm, pos, true);
|
||||
return menu_wd->_m_manipulate_sub(0, true);
|
||||
}
|
||||
|
||||
int send_shortkey(nana::char_t key)
|
||||
@ -969,63 +986,51 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
void _m_make_mouse_event()
|
||||
bool _m_manipulate_sub(unsigned long delay_ms, bool forced)
|
||||
{
|
||||
state_.mouse_pos = API::cursor_position();
|
||||
events().mouse_move.connect_unignorable([this]{
|
||||
_m_mouse_event();
|
||||
});
|
||||
}
|
||||
auto & drawer = get_drawer_trigger();
|
||||
::nana::point pos;
|
||||
unsigned long tmstamp;
|
||||
|
||||
void _m_mouse_event()
|
||||
{
|
||||
nana::point pos = API::cursor_position();
|
||||
if(pos != state_.mouse_pos)
|
||||
auto menu_ptr = drawer.get_sub(pos, tmstamp);
|
||||
|
||||
if (menu_ptr == submenu_.object)
|
||||
return false;
|
||||
|
||||
if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms))
|
||||
return false;
|
||||
|
||||
if (submenu_.object && (menu_ptr != submenu_.object))
|
||||
{
|
||||
menu_window * root = this;
|
||||
while(root->submenu_.parent)
|
||||
root = root->submenu_.parent;
|
||||
root->state_.auto_popup_submenu = true;
|
||||
|
||||
state_.mouse_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced)
|
||||
{
|
||||
auto & mdtrigger = get_drawer_trigger();
|
||||
if(submenu_.object && (sbm != submenu_.object))
|
||||
{
|
||||
mdtrigger.set_sub_window(false);
|
||||
drawer.set_sub_window(false);
|
||||
submenu_.child->close();
|
||||
submenu_.child = nullptr;
|
||||
submenu_.object = nullptr;
|
||||
}
|
||||
|
||||
if(sbm)
|
||||
if (menu_ptr)
|
||||
{
|
||||
menu_window * root = this;
|
||||
while(root->submenu_.parent)
|
||||
while (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;
|
||||
sbm->gaps = mdtrigger.data()->gaps;
|
||||
pos.x += sbm->gaps.x;
|
||||
pos.y += sbm->gaps.y;
|
||||
menu_ptr->item_pixels = drawer.data()->item_pixels;
|
||||
menu_ptr->gaps = drawer.data()->gaps;
|
||||
pos += menu_ptr->gaps;
|
||||
|
||||
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;
|
||||
submenu_.child = & mwnd;
|
||||
submenu_.child = &mwnd;
|
||||
submenu_.child->submenu_.parent = this;
|
||||
submenu_.object = sbm;
|
||||
submenu_.object = menu_ptr;
|
||||
|
||||
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
|
||||
|
||||
mwnd.popup(*sbm, state_.owner_menubar);
|
||||
mdtrigger.set_sub_window(true);
|
||||
if(forced)
|
||||
mwnd.popup(*menu_ptr, state_.owner_menubar);
|
||||
drawer.set_sub_window(true);
|
||||
if (forced)
|
||||
mwnd.goto_next(true);
|
||||
|
||||
return true;
|
||||
@ -1034,17 +1039,16 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
void _m_check_repeatly()
|
||||
void _m_open_sub(unsigned delay_ms) //check_repeatly
|
||||
{
|
||||
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);
|
||||
drawer.track_mouse(pos.x, pos.y);
|
||||
menu_type* sbm = drawer.retrive_sub_menu(pos, 500);
|
||||
_m_show_submenu(sbm, pos, false);
|
||||
get_drawer_trigger().track_mouse(pos);
|
||||
|
||||
_m_manipulate_sub(delay_ms, false);
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user