improve dockable place
add a new API::at_safe_place()
This commit is contained in:
parent
5d2127e613
commit
460490040e
@ -161,6 +161,9 @@ namespace detail
|
||||
std::vector<std::pair<core_window_t*, unsigned long>> shortkeys(core_window_t*, bool with_children);
|
||||
|
||||
core_window_t* find_shortkey(native_window_type, unsigned long key);
|
||||
|
||||
void set_safe_place(core_window_t* wd, std::function<void()>&& fn);
|
||||
void call_safe_place(unsigned thread_id);
|
||||
private:
|
||||
void _m_disengage(core_window_t*, core_window_t* for_new);
|
||||
void _m_destroy(core_window_t*);
|
||||
|
||||
@ -298,6 +298,8 @@ namespace API
|
||||
|
||||
bool ignore_mouse_focus(window, bool ignore); ///< Enables/disables the mouse focus, it returns the previous state
|
||||
bool ignore_mouse_focus(window); ///< Determines whether the mouse focus is enabled
|
||||
|
||||
void at_safe_place(window, std::function<void()>);
|
||||
}//end namespace API
|
||||
}//end namespace nana
|
||||
|
||||
|
||||
@ -379,6 +379,9 @@ namespace nana
|
||||
|
||||
void push_back(std::string text, ::nana::any par = {});
|
||||
void push_front(std::string text, ::nana::any par = {});
|
||||
|
||||
std::size_t selected() const;
|
||||
void erase(std::size_t pos, bool close_attached = true);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1207,8 +1207,11 @@ namespace detail
|
||||
if(context) context->event_window = pre_event_window;
|
||||
}
|
||||
|
||||
auto thread_id = ::nana::system::this_thread_id()
|
||||
brock.wd_manager.call_safe_place(thread_id);
|
||||
|
||||
if(msgwnd)
|
||||
brock.wd_manager.remove_trash_handle(::nana::system::this_thread_id());
|
||||
brock.wd_manager.remove_trash_handle(thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -413,6 +413,7 @@ namespace detail
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
wd_manager.call_safe_place(tid);
|
||||
wd_manager.remove_trash_handle(tid);
|
||||
if (msg.message == WM_DESTROY && msg.hwnd == native_handle)
|
||||
break;
|
||||
@ -432,6 +433,7 @@ namespace detail
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
wd_manager.call_safe_place(tid);
|
||||
wd_manager.remove_trash_handle(tid);
|
||||
}//end while
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ namespace detail
|
||||
handle_manager<core_window_t*, window_manager, window_handle_deleter> wd_register;
|
||||
paint::image default_icon_big;
|
||||
paint::image default_icon_small;
|
||||
|
||||
std::map<core_window_t*, std::vector<std::function<void()>>> safe_place;
|
||||
};
|
||||
//end struct wdm_private_impl
|
||||
|
||||
@ -1192,6 +1194,36 @@ namespace detail
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void window_manager::set_safe_place(core_window_t* wd, std::function<void()>&& fn)
|
||||
{
|
||||
if (fn)
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
if (!available(wd))
|
||||
return;
|
||||
|
||||
impl_->safe_place[wd].emplace_back(std::move(fn));
|
||||
}
|
||||
}
|
||||
|
||||
void window_manager::call_safe_place(unsigned thread_id)
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
for (auto i = impl_->safe_place.begin(); i != impl_->safe_place.end();)
|
||||
{
|
||||
if (i->first->thread_id == thread_id)
|
||||
{
|
||||
for (auto & fn : i->second)
|
||||
fn();
|
||||
|
||||
i = impl_->safe_place.erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
bool check_tree(basic_window* wd, basic_window* const cond)
|
||||
{
|
||||
if (wd == cond) return true;
|
||||
|
||||
@ -1717,13 +1717,27 @@ namespace nana
|
||||
|
||||
}
|
||||
|
||||
void notify_move_stopped()
|
||||
void notify_move_stopped() override
|
||||
{
|
||||
if (_m_dockable() && dockable_field && dockable_field->dockarea)
|
||||
dockable_field->dockarea->dock();
|
||||
|
||||
indicator_.docker.reset();
|
||||
}
|
||||
|
||||
void request_close() override
|
||||
{
|
||||
auto window_handle = dockable_field->dockarea->handle();
|
||||
|
||||
//a workaround for capture
|
||||
auto ptr = dockable_field->dockarea.release();
|
||||
API::at_safe_place(window_handle, [this, ptr]
|
||||
{
|
||||
decltype(dockable_field->dockarea) del(ptr);
|
||||
});
|
||||
|
||||
API::close_window(window_handle);
|
||||
}
|
||||
private:
|
||||
bool _m_indicator() const
|
||||
{
|
||||
|
||||
@ -57,12 +57,19 @@ namespace nana
|
||||
virtual void notify_dock() = 0;
|
||||
virtual void notify_move() = 0;
|
||||
virtual void notify_move_stopped() = 0;
|
||||
|
||||
//a dockarea requests to close the dockpane
|
||||
virtual void request_close() = 0;
|
||||
};
|
||||
|
||||
class dockcaption_dtrigger
|
||||
: public drawer_trigger
|
||||
{
|
||||
public:
|
||||
void on_close(std::function<void()>&& fn)
|
||||
{
|
||||
close_fn_ = std::move(fn);
|
||||
}
|
||||
private:
|
||||
virtual void attached(widget_reference wdg, graph_reference graph) override
|
||||
{
|
||||
@ -84,10 +91,18 @@ namespace nana
|
||||
//draw x button
|
||||
auto r = _m_button_area();
|
||||
if (x_pointed_)
|
||||
graph.rectangle(r, true, colors::red);
|
||||
{
|
||||
color xclr = colors::red;
|
||||
|
||||
if(x_state_ == ::nana::mouse_action::pressed)
|
||||
xclr = xclr.blend(colors::white, 0.8);
|
||||
|
||||
graph.rectangle(r, true, xclr);
|
||||
}
|
||||
|
||||
r.x += (r.width - 16) / 2;
|
||||
r.y = (r.height - 16) / 2;
|
||||
|
||||
x_icon_.draw(graph, colors::red, colors::white, r, element_state::normal);
|
||||
}
|
||||
|
||||
@ -105,6 +120,29 @@ namespace nana
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void mouse_down(graph_reference graph, const arg_mouse&) override
|
||||
{
|
||||
if (!x_pointed_)
|
||||
return;
|
||||
|
||||
x_state_ = ::nana::mouse_action::pressed;
|
||||
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void mouse_up(graph_reference graph, const arg_mouse&) override
|
||||
{
|
||||
if (!x_pointed_)
|
||||
return;
|
||||
|
||||
x_state_ = ::nana::mouse_action::over;
|
||||
refresh(graph);
|
||||
API::lazy_refresh();
|
||||
|
||||
close_fn_();
|
||||
}
|
||||
private:
|
||||
::nana::rectangle _m_button_area() const
|
||||
{
|
||||
@ -118,12 +156,21 @@ namespace nana
|
||||
window window_handle_;
|
||||
std::unique_ptr<paint::text_renderer> text_rd_;
|
||||
bool x_pointed_{ false };
|
||||
::nana::mouse_action x_state_{ ::nana::mouse_action::normal };
|
||||
facade<element::x_icon> x_icon_;
|
||||
|
||||
std::function<void()> close_fn_;
|
||||
};
|
||||
|
||||
class dockarea_caption
|
||||
: public widget_object < category::widget_tag, dockcaption_dtrigger >
|
||||
{};
|
||||
{
|
||||
public:
|
||||
void on_close(std::function<void()> fn)
|
||||
{
|
||||
get_drawer_trigger().on_close(std::move(fn));
|
||||
}
|
||||
};
|
||||
|
||||
class dock_page
|
||||
: public form
|
||||
@ -158,6 +205,22 @@ namespace nana
|
||||
base_type::create(parent, true);
|
||||
this->caption("dockarea");
|
||||
caption_.create(*this, true);
|
||||
caption_.on_close([this]
|
||||
{
|
||||
bool destroy_dockarea = false;
|
||||
try
|
||||
{
|
||||
tabbar_->erase(tabbar_->selected());
|
||||
destroy_dockarea = (0 == tabbar_->length());
|
||||
}
|
||||
catch (std::out_of_range&)
|
||||
{
|
||||
destroy_dockarea = true;
|
||||
}
|
||||
|
||||
if (destroy_dockarea)
|
||||
notifier_->request_close();
|
||||
});
|
||||
|
||||
this->events().resized([this](const arg_resized& arg)
|
||||
{
|
||||
|
||||
@ -1314,5 +1314,10 @@ namespace API
|
||||
internal_scope_guard lock;
|
||||
return (restrict::window_manager.available(iwd) ? iwd->flags.ignore_mouse_focus : false);
|
||||
}
|
||||
|
||||
void at_safe_place(window wd, std::function<void()> fn)
|
||||
{
|
||||
restrict::window_manager.set_safe_place(reinterpret_cast<restrict::core_window_t*>(wd), std::move(fn));
|
||||
}
|
||||
}//end namespace API
|
||||
}//end namespace nana
|
||||
|
||||
@ -1555,15 +1555,7 @@ namespace nana
|
||||
{
|
||||
auto& items = get_drawer_trigger().get_model()->items();
|
||||
internal_scope_guard lock;
|
||||
|
||||
std::size_t off = 0;
|
||||
auto i = items.cbegin(), end = items.cend();
|
||||
while (i != end)
|
||||
{
|
||||
++i;
|
||||
++off;
|
||||
}
|
||||
return off;
|
||||
return static_cast<std::size_t>(std::distance(items.cbegin(), items.cend()));
|
||||
}
|
||||
|
||||
//modifiers
|
||||
@ -1613,5 +1605,54 @@ namespace nana
|
||||
items.emplace_front(std::move(text), std::move(any));
|
||||
API::refresh_window(handle());
|
||||
}
|
||||
|
||||
std::size_t tabbar_lite::selected() const
|
||||
{
|
||||
auto model = get_drawer_trigger().get_model();
|
||||
internal_scope_guard lock;
|
||||
|
||||
return model->get_indexes().active_pos;
|
||||
}
|
||||
|
||||
void tabbar_lite::erase(std::size_t pos, bool close_attached)
|
||||
{
|
||||
auto model = get_drawer_trigger().get_model();
|
||||
internal_scope_guard lock;
|
||||
|
||||
const auto len = length();
|
||||
|
||||
if (len <= pos)
|
||||
throw std::out_of_range("tabbar_lite: out of range");
|
||||
|
||||
auto active_pos = model->get_indexes().active_pos;
|
||||
|
||||
if (pos == active_pos)
|
||||
{
|
||||
if (active_pos + 1 == len)
|
||||
{
|
||||
if (active_pos)
|
||||
--active_pos;
|
||||
else
|
||||
active_pos = npos;
|
||||
}
|
||||
}
|
||||
else if (pos < active_pos)
|
||||
--active_pos;
|
||||
|
||||
model->get_indexes().active_pos = active_pos;
|
||||
|
||||
auto i = model->items().cbefore_begin();
|
||||
std::advance(i, pos);
|
||||
|
||||
auto attached_wd = std::next(i)->attached_window;
|
||||
|
||||
model->items().erase_after(i);
|
||||
|
||||
model->show_attached_window();
|
||||
API::refresh_window(handle());
|
||||
|
||||
if (close_attached && attached_wd)
|
||||
API::close_window(attached_wd);
|
||||
}
|
||||
//end class tabbar
|
||||
}//end namespace nana
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user