improve dockable place

add a new API::at_safe_place()
This commit is contained in:
Jinhao 2015-09-20 23:21:44 +08:00
parent 5d2127e613
commit 460490040e
10 changed files with 181 additions and 13 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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