improve dockpane factory

This commit is contained in:
Jinhao 2015-09-19 05:18:15 +08:00
parent 44a067fd51
commit 5d2127e613
3 changed files with 109 additions and 36 deletions

View File

@ -127,15 +127,16 @@ namespace nana
/// Add a panel factory
template<typename Panel, typename ...Args>
void dock(const std::string& dockname, Args&& ... args)
place& dock(const std::string& dockname, const std::string& factory_name, Args&& ... args)
{
dock(dockname, std::bind([](window parent, Args & ... args)
return dock(dockname, factory_name, std::bind([](window parent, Args & ... args)
{
return std::unique_ptr<widget>(new Panel(parent, std::forward<Args>(args)...));
}, std::placeholders::_1, args...));
}
void dock(const std::string& dockname, std::function<std::unique_ptr<widget>(window)> factory);
place& dock(const std::string& dockname, std::string factory_name, std::function<std::unique_ptr<widget>(window)> factory);
place& dock_create(const std::string& factory);
private:
implement * impl_;
};

View File

@ -450,6 +450,7 @@ namespace nana
std::unique_ptr<division> root_division;
std::map<std::string, field_gather*> fields;
std::map<std::string, field_dock*> docks;
std::map<std::string, field_dock*> dock_factoris;
//A temporary pointer used to refer to a specified div object which
//will be deleted in modification process.
@ -597,8 +598,9 @@ namespace nana
{
public:
div_dockpane * attached{ nullptr }; //attached div object
place_parts::dockarea dockarea; //the dockable widget
div_dockpane * attached{ nullptr }; //attached div object
std::unique_ptr<place_parts::dockarea> dockarea; //the dockable widget
std::map<std::string, std::function<std::unique_ptr<widget>(window)>> factories; //factories for dockpane
};//end class field_dock
@ -1559,13 +1561,14 @@ namespace nana
impl_ptr_{impl}
{
dir = pane_dir;
this->display = false;
}
~div_dockpane()
{
if (dockable_field)
{
dockable_field->dockarea.close();
dockable_field->dockarea.reset();
dockable_field->attached = nullptr;
}
}
@ -1586,6 +1589,8 @@ namespace nana
}
auto & dockarea = dockable_field->dockarea;
/*
if (!created_)
{
created_ = true;
@ -1594,6 +1599,10 @@ namespace nana
if (!dockarea.empty() && !dockarea.floating())
dockarea.move(this->field_area);
*/
if (dockarea && !dockarea->floating())
dockarea->move(this->field_area);
}
private:
//Implement dock_notifier_interface
@ -1710,8 +1719,8 @@ namespace nana
void notify_move_stopped()
{
if (_m_dockable() && dockable_field)
dockable_field->dockarea.dock();
if (_m_dockable() && dockable_field && dockable_field->dockarea)
dockable_field->dockarea->dock();
indicator_.docker.reset();
}
@ -2514,7 +2523,7 @@ namespace nana
for (auto& e : docks_to_be_closed)
{
e.second->dockarea.close();
e.second->dockarea.reset();
e.second->attached->dockable_field = nullptr;
e.second->attached = nullptr;
}
@ -2747,7 +2756,7 @@ namespace nana
return field(name);
}
void place::dock(const std::string& name, std::function<std::unique_ptr<widget>(window)> factory)
place& place::dock(const std::string& name, std::string factory_name, std::function<std::unique_ptr<widget>(window)> factory)
{
//check the name, it throws std::invalid_argument
//if name violate the naming convention.
@ -2757,7 +2766,16 @@ namespace nana
if (!dock_ptr)
dock_ptr = new implement::field_dock;
dock_ptr->dockarea.add_factory(std::move(factory));
//Register the factory if it has a name
if (!factory_name.empty())
{
auto i = impl_->dock_factoris.find(factory_name);
if (i != impl_->dock_factoris.end())
throw std::invalid_argument("nana::place - the specified factory name(" + factory_name + ") already exists");
impl_->dock_factoris[factory_name] = dock_ptr;
dock_ptr->factories[factory_name].swap(factory);
}
auto div = dynamic_cast<implement::div_dockpane*>(impl_->search_div_name(impl_->root_division.get(), name));
if (div)
@ -2765,6 +2783,45 @@ namespace nana
dock_ptr->attached = div;
div->dockable_field = dock_ptr;
}
//Create the pane if it has not a name
if (factory_name.empty())
{
dock_ptr->attached->set_display(true);
impl_->collocate();
if (!dock_ptr->dockarea)
{
dock_ptr->dockarea.reset(new ::nana::place_parts::dockarea);
dock_ptr->dockarea->create(impl_->window_handle, dock_ptr->attached);
dock_ptr->dockarea->move(dock_ptr->attached->field_area);
}
dock_ptr->dockarea->add_pane(factory);
}
return *this;
}
place& place::dock_create(const std::string& factory)
{
auto i = impl_->dock_factoris.find(factory);
if (i == impl_->dock_factoris.end())
throw std::invalid_argument("nana::place - invalid factory name(" + factory + ")");
auto dock_ptr = i->second;
dock_ptr->attached->set_display(true);
impl_->collocate();
if (!dock_ptr->dockarea)
{
dock_ptr->dockarea.reset(new ::nana::place_parts::dockarea);
dock_ptr->dockarea->create(impl_->window_handle, dock_ptr->attached);
dock_ptr->dockarea->move(dock_ptr->attached->field_area);
}
dock_ptr->dockarea->add_pane(i->second->factories[factory]);
return *this;
}
//end class place
}//end namespace nana

View File

@ -148,12 +148,7 @@ namespace nana
struct panel
{
factory factory_fn;
std::unique_ptr<widget> widget_ptr;
panel(factory && fn)
: factory_fn(std::move(fn))
{}
};
public:
void create(window parent, place_parts::dock_notifier_interface* notifier)
@ -229,29 +224,49 @@ namespace nana
}
});
if (panels_.size() > 1)
tabbar_.reset(new tabbar_lite(*this));
std::size_t pos = 0;
for (auto & pn : panels_)
{
if (!pn.widget_ptr)
{
pn.widget_ptr = pn.factory_fn(*this);
if (tabbar_)
{
tabbar_->push_back(::nana::charset(pn.widget_ptr->caption()));
tabbar_->attach(pos++, pn.widget_ptr->handle());
//tabbar_->push_back(pn.widget_ptr->caption());
//tabbar_->relate(pos++, pn.widget_ptr->handle());
}
}
}
}
void add_factory(factory && fn)
void add_pane(factory & fn)
{
panels_.emplace_back(std::move(fn));
rectangle r{ point(), this->size()};
//get a rectangle excluding caption
r.y = 20;
if (r.height > 20)
r.height -= 20;
else
r.height = 0;
if (!tabbar_ && panels_.size() > 0)
{
tabbar_.reset(new tabbar_lite(*this));
tabbar_->move({ 0, r.bottom() - 20, r.width, 20 });
r.height -= 20;
std::size_t pos = 0;
for (auto & pn : panels_)
{
tabbar_->push_back(::nana::charset(pn.widget_ptr->caption()));
tabbar_->attach(pos++, *pn.widget_ptr);
}
}
auto wdg = fn(*this);
if (tabbar_)
{
tabbar_->push_back(::nana::charset(wdg->caption()));
tabbar_->attach(panels_.size(), *wdg);
}
panels_.emplace_back();
panels_.back().widget_ptr.swap(wdg);
for (auto & pn : panels_)
{
if (pn.widget_ptr)
pn.widget_ptr->move(r);
}
}
void float_away(const ::nana::point& move_pos)