Merge branch 'qPCR4vir-hotfixes-1.0.2' into hotfixes-1.0.2

This commit is contained in:
Jinhao 2015-05-09 05:07:23 +08:00
commit e31616e5dd
3 changed files with 203 additions and 80 deletions

View File

@ -28,6 +28,10 @@ Run it! All dependencies will be resovled automatically by biicode! Amazing, isn
The best way to get help with Nana library is by visiting http://nanapro.org/help.htm The best way to get help with Nana library is by visiting http://nanapro.org/help.htm
## Sending a Pull Request ?
This project is encourage you to contribute it through sending a pull request! There is a simple rule, please **don't** directly commit your contributions to the **master** branch. According to your commits, please choose the **hotfixes** branch or the **develop** branch. Thank you!
## Introduction to the Repository ## Introduction to the Repository
There are two main branches with an infinite lifetime: There are two main branches with an infinite lifetime:

View File

@ -163,9 +163,9 @@ namespace nana
typedef std::vector<index_pair> selection; typedef std::vector<index_pair> selection;
//struct essence_t /// struct essence_t
//@brief: this struct gives many data for listbox, ///@brief: this struct gives many data for listbox,
// the state of the struct does not effect on member funcions, therefore all data members are public. /// the state of the struct does not effect on member funcions, therefore all data members are public.
struct essence_t; struct essence_t;
struct category_t; struct category_t;
@ -366,6 +366,7 @@ namespace nana
return iter; return iter;
} }
/// Appends one item at the end of this category with the specifies text in the column fields
void append(std::initializer_list<nana::string>); void append(std::initializer_list<nana::string>);
size_type columns() const; size_type columns() const;
@ -373,6 +374,9 @@ namespace nana
cat_proxy& text(nana::string); cat_proxy& text(nana::string);
nana::string text() const; nana::string text() const;
cat_proxy & select(bool);
bool selected() const;
/// Behavior of a container /// Behavior of a container
void push_back(nana::string); void push_back(nana::string);
@ -473,16 +477,54 @@ namespace nana
color_proxy header_grabbed{ static_cast<color_rgb>(0x8BD6F6)}; color_proxy header_grabbed{ static_cast<color_rgb>(0x8BD6F6)};
color_proxy header_floated{ static_cast<color_rgb>(0xBABBBC)}; color_proxy header_floated{ static_cast<color_rgb>(0xBABBBC)};
color_proxy item_selected{ static_cast<color_rgb>(0xD5EFFC) }; color_proxy item_selected{ static_cast<color_rgb>(0xD5EFFC) };
unsigned max_header_width{3000}, /// \todo how to implement some geometrical parameters ??
ext_w = 5;
}; };
} }
}//end namespace drawerbase }//end namespace drawerbase
/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items. /*! \class listbox
\brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items.
A category is a text with can be \a selected, \a checked and \a expanded to show the items. A category is a text with can be \a selected, \a checked and \a expanded to show the items.
An item is formed by \a column-fields, each corresponding to one of the \a headers. An item is formed by \a column-fields, each corresponding to one of the \a headers.
An item can be \a selected and \a checked. An item can be \a selected and \a checked.
The user can \a drag the header to \a reisize it or to \a reorganize it. The user can \a drag the header to \a resize it or to \a reorganize it.
By \a clicking on a header the list get \a reordered, first up, and then down alternatively. By \a clicking on one header the list get \a reordered, first up, and then down alternatively.
1. The resolver is used to resolute an object of the specified type for a listbox item.
3. nana::listbox creates the category 0 by default. The member functions without the categ parameter operate the items that belong to category 0.
4. A sort compare is used for sorting the items. It is a strict weak ordering comparer that must meet the requirement:
Irreflexivity (comp(x, x) returns false)
and
antisymmetry(comp(a, b) != comp(b, a) returns true)
A simple example.
bool sort_compare( const nana::string& s1, nana::any*,
const nana::string& s2, nana::any*, bool reverse)
{
return (reverse ? s1 > s2 : s1 < s2);
}
listbox.set_sort_compare(0, sort_compare);
The listbox supports attaching a customer's object for each item, therefore the items can be
sorted by comparing these customer's object.
bool sort_compare( const nana::string&, nana::any* o1,
const nana::string&, nana::any* o2, bool reverse)
{
if(o1 && o2) //some items may not attach a customer object.
{
int * i1 = o1->get<int>();
int * i2 = o2->get<int>();
return (i1 && i2 && (reverse ? *i1 > *i2 : *i1 < *i2));
;//some types may not be int.
}
return false;
}
listbox.anyobj(0, 0, 10); //the type of customer's object is int.
listbox.anyobj(0, 0, 20);
\todo doc: actualize this example listbox.at(0)...
\see nana::drawerbase::listbox::cat_proxy
\see nana::drawerbase::listbox::item_proxy
\example listbox_Resolver.cpp
*/ */
class listbox class listbox
: public widget_object<category::widget_tag, drawerbase::listbox::trigger, drawerbase::listbox::listbox_events, drawerbase::listbox::scheme>, : public widget_object<category::widget_tag, drawerbase::listbox::trigger, drawerbase::listbox::listbox_events, drawerbase::listbox::scheme>,
@ -504,14 +546,17 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
listbox(window, bool visible); listbox(window, bool visible);
listbox(window, const rectangle& = {}, bool visible = true); listbox(window, const rectangle& = {}, bool visible = true);
void auto_draw(bool); ///<Set state: Redraw automatically after an operation? void auto_draw(bool); ///< Set state: Redraw automatically after an operation?
void append_header(nana::string, unsigned width = 120);///<Appends a new column with a header text and the specified width at the end /// Appends a new column with a header text and the specified width at the end, and return it position
listbox& header_width(size_type pos, unsigned pixels); size_type append_header(nana::string header_text, unsigned width = 120);
unsigned header_width(size_type pos) const; listbox& header_width(size_type position, unsigned pixels);
unsigned header_width(size_type position) const;
unsigned auto_width(size_type position, unsigned max=3000);
cat_proxy append(nana::string); ///<Appends a new category at the end
void append(std::initializer_list<nana::string>); ///<Appends categories at the end cat_proxy append(nana::string); ///< Appends a new category at the end
void append(std::initializer_list<nana::string>); ///< Appends categories at the end
cat_proxy insert(cat_proxy, nana::string); cat_proxy insert(cat_proxy, nana::string);
cat_proxy at(size_type pos) const; cat_proxy at(size_type pos) const;

View File

@ -399,20 +399,19 @@ namespace nana
return{}; return{};
} }
void create(nana::string&& text, unsigned pixels) size_type create(nana::string&& text, unsigned pixels)
{ {
cont_.emplace_back(std::move(text), pixels, static_cast<size_type>(cont_.size())); cont_.emplace_back(std::move(text), pixels, static_cast<size_type>(cont_.size()));
return cont_.back().index;
} }
void item_width(size_type pos, unsigned width) void item_width(size_type pos, unsigned width)
{ {
if (pos >= cont_.size())
return;
for(auto & m : cont_) for(auto & m : cont_)
{
if(m.index == pos) if(m.index == pos)
{
m.pixels = width; m.pixels = width;
return;
} }
} }
@ -1592,31 +1591,7 @@ namespace nana
} }
/// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_ /// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_
bool categ_selected(size_type cat, bool sel) bool categ_selected(size_type cat, bool sel);
{
bool changed = false;
auto & items = _m_at(cat)->items;
index_pair pos(cat, 0);
for(auto & m : items)
{
if(m.flags.selected != sel)
{
m.flags.selected = sel;
arg_listbox arg{ item_proxy(ess_, pos), sel };
wd_ptr()->events().selected.emit(arg);
changed = true;
if (sel) // not check for single_selection_
last_selected_abs = pos;
else if (last_selected_abs == pos)
last_selected_abs.set_both(npos);
}
++pos.item;
}
return changed;
}
void reverse_categ_selected(size_type categ) void reverse_categ_selected(size_type categ)
{ {
@ -1644,7 +1619,20 @@ namespace nana
/// absolute position of the last displayed item /// absolute position of the last displayed item
index_pair last_displ() const index_pair last_displ() const
{ {
return absolute ( last_displ() ); return absolute ( last() );
}
/// can be used as the absolute position of the first absolute item, or as the display pos of the first displayed item
index_pair first() const
{
index_pair fst{0,npos};
good_item(fst,fst);
return fst;
}
/// absolute position of the first displayed item
index_pair first_displ() const
{
return absolute ( first() );
} }
bool good(size_type cat) const bool good(size_type cat) const
@ -1656,32 +1644,32 @@ namespace nana
{ {
return ((pos.cat < list_.size()) && (pos.item < size_item(pos.cat))); return ((pos.cat < list_.size()) && (pos.item < size_item(pos.cat)));
} }
/// if good return the same item (in arg item), or just the next cat and true, but If fail return false
bool good_item(index_pair pos, index_pair& item) const bool good_item(index_pair pos, index_pair& item) const
{ {
if (!good(pos.cat)) if (!good(pos.cat))
return false; return false; // cat out of range
if (pos.is_category()) if (pos.is_category())
{ {
item = pos; item = pos; // return the cat self
if (0 == pos.cat) if (0 == pos.cat) // but for cat 0 return first item
item.item = 0; item.item = 0; // let check this is good
else
return true; return true;
} }
auto i = _m_at(pos.cat); auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat
if (pos.item < i->items.size()) if (pos.item < i->items.size())
{ {
item = pos; item = pos; // good item, return it
return true; return true;
} }
if (++i == list_.end()) if (++i == list_.end()) // item out of range and no more cat
return false; return false;
item.cat = pos.cat + 1; item.cat = pos.cat + 1; // select the next cat
item.item = npos; item.item = npos;
return true; return true;
} }
@ -1689,7 +1677,7 @@ namespace nana
///Translate relative position (position in display) into absolute position (original data order) ///Translate relative position (position in display) into absolute position (original data order)
size_type absolute(const index_pair& display_pos) const size_type absolute(const index_pair& display_pos) const
{ {
if(sorted_index_ == npos) if(sorted_index_ == npos || display_pos.item == npos)
return display_pos.item ; return display_pos.item ;
auto & catobj = *_m_at(display_pos.cat); auto & catobj = *_m_at(display_pos.cat);
@ -1739,13 +1727,12 @@ namespace nana
return true; return true;
} }
if(list_.size() <= from.cat) return false;
if(from.is_category()) if(from.is_category())
{ {
// this is a category, so... // this is a category, so...
// and offs is not 0, this category would not be candidated. // and offs is not 0, this category would not be candidated.
// the algorithm above to calc the offset item is always starting with a item. // the algorithm above to calc the offset item is always starting with a item.
// we can not select, navigate or highlight begining from a cat?
--offs; --offs;
from.item = 0; from.item = 0;
} }
@ -1754,7 +1741,7 @@ namespace nana
if(icat->expand) if(icat->expand)
{ {
std::size_t item_left_in_this_cat = icat->items.size() -1- from.item; std::size_t item_left_in_this_cat = icat->items.size()- from.item -1;
if(offs <= item_left_in_this_cat ) if(offs <= item_left_in_this_cat )
{ {
item = from; item = from;
@ -1763,14 +1750,15 @@ namespace nana
} }
else else
{ {
offs -= item_left_in_this_cat ; offs -= (item_left_in_this_cat+1) ;
item = from; item = from;
item.item += item_left_in_this_cat ; item.item += item_left_in_this_cat ;// select the last item
} }
} }
++from.cat; ++from.cat;
++icat; ++icat;
for(; icat != list_.end(); ++icat, ++from.cat) for(; icat != list_.end(); ++icat, ++from.cat)
{ {
item.cat = from.cat; item.cat = from.cat;
@ -2195,7 +2183,7 @@ namespace nana
} }
else else
{ {
new_where.second = (y - header_visible_px() + 1) / item_size; new_where.second = ((y + 1) - header_visible_px()) / item_size; // y>1 !
new_where.first = parts::lister; new_where.first = parts::lister;
if(checkable) if(checkable)
{ {
@ -2316,6 +2304,28 @@ namespace nana
break; break;
} }
} }
unsigned auto_width(size_type pos, unsigned max=3000) /// \todo introduce parametr max_header_width
{
unsigned max_w{0} ;
for (const auto &cat : lister.cat_container())
for (const auto &it : cat.items )
{
if (pos >= it.cells.size()) continue;
// precalcule text geometry
unsigned ts = static_cast<unsigned> ( graph->text_extent_size(it.cells[pos].text).width);
if (max_w < ts)
max_w = ts;
}
if (!max_w) return 0;
unsigned ext_w = scheme_ptr->ext_w ;
if( pos == 0 && checkable) // only before the first column (display_order=0 ?)
ext_w += 18;
header.item_width(pos, max_w + ext_w + 1 < max ? max_w + ext_w + 1 : max);
return max_w;
}
private: private:
void _m_answer_scroll(const arg_mouse& arg) void _m_answer_scroll(const arg_mouse& arg)
{ {
@ -2471,6 +2481,22 @@ namespace nana
return list_str ; return list_str ;
} }
bool es_lister::categ_selected(size_type cat, bool sel)
{
bool changed = false; // we need this??
cat_proxy cpx{ess_,cat};
for (item_proxy &it : cpx )
{
if (it.selected() != sel)
changed = true;
it.select(sel);
}
last_selected_abs = last_selected_dpl = index_pair {cat, npos};
return changed; // we need this??
}
class drawer_header_impl class drawer_header_impl
{ {
@ -2903,7 +2929,7 @@ namespace nana
cell_txtcolor = m_cell.custom_format->fgcolor; cell_txtcolor = m_cell.custom_format->fgcolor;
} }
int ext_w = 5; int ext_w = essence_->scheme_ptr->ext_w;
if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?)
{ {
ext_w += 18; ext_w += 18;
@ -3302,6 +3328,14 @@ namespace nana
void trigger::dbl_click(graph_reference graph, const arg_mouse&) void trigger::dbl_click(graph_reference graph, const arg_mouse&)
{ {
if (essence_->pointer_where.first == essence_t::parts::header)
if (cursor::size_we == essence_->lister.wd_ptr()->cursor())
{
if (essence(). auto_width(drawer_header_->item_spliter() )) // ? in order
essence().update();
return;
}
if (essence_->pointer_where.first != essence_t::parts::lister) if (essence_->pointer_where.first != essence_t::parts::lister)
return; return;
@ -3370,21 +3404,35 @@ namespace nana
if (! scrl.make_page_scroll(!up)) if (! scrl.make_page_scroll(!up))
return; return;
essence_->lister.select_for_all(false); essence_->lister.select_for_all(false);
if (up)
item_proxy {essence_, essence_->scroll_y_abs()}.select(true);
else
{
index_pair idx{essence_->scroll_y_dpl()}; index_pair idx{essence_->scroll_y_dpl()};
if (!up)
essence_->lister.forward(idx, scrl.range()-1, idx); essence_->lister.forward(idx, scrl.range()-1, idx);
item_proxy::from_display(essence_,idx).select(true);
} if (idx.is_item())
item_proxy::from_display(essence_, idx).select(true);
else
if(!essence_->lister.single_selection())
essence_->lister.categ_selected(idx.cat, true);
essence_->trace_last_selected_item ();
break; break;
} }
case keyboard::os_home: case keyboard::os_home:
{
essence_->lister.select_for_all(false); essence_->lister.select_for_all(false);
item_proxy::from_display(essence_, {0,0}).select(true);
index_pair frst{essence_->lister.first()};
if (frst.is_item())
item_proxy::from_display(essence_, frst).select(true);
else
if(!essence_->lister.single_selection())
essence_->lister.categ_selected(frst.cat, true);
essence_->trace_last_selected_item (); essence_->trace_last_selected_item ();
break; break;
}
case keyboard::os_end: case keyboard::os_end:
essence_->lister.select_for_all(false); essence_->lister.select_for_all(false);
item_proxy::from_display(essence_, essence_->lister.last()).select(true); item_proxy::from_display(essence_, essence_->lister.last()).select(true);
@ -3436,7 +3484,7 @@ namespace nana
{ {
auto i = ess_->lister.cat_container().begin(); auto i = ess_->lister.cat_container().begin();
std::advance(i, pos.cat); std::advance(i, pos.cat);
cat_ = &(*i); cat_ = &(*i); // what is pos is a cat?
} }
} }
@ -3481,7 +3529,7 @@ namespace nana
/// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected
item_proxy & item_proxy::select(bool s) item_proxy & item_proxy::select(bool s)
{ {
auto & m = cat_->items.at(pos_.item); // a ref to the real item auto & m = cat_->items.at(pos_.item); // a ref to the real item // what is pos is a cat?
if(m.flags.selected == s) return *this; // ignore if no change if(m.flags.selected == s) return *this; // ignore if no change
m.flags.selected = s; // actually change selection m.flags.selected = s; // actually change selection
@ -3715,6 +3763,24 @@ namespace nana
} }
} }
cat_proxy & cat_proxy::select(bool sel)
{
for (item_proxy &it : *this )
it.select(sel);
ess_->lister.last_selected_abs =
ess_->lister.last_selected_dpl = index_pair {this->pos_, npos};
return *this;
}
bool cat_proxy::selected() const
{
for (item_proxy &it : *this )
if (!it.selected())
return false;
return true;
}
auto cat_proxy::columns() const -> size_type auto cat_proxy::columns() const -> size_type
{ {
return ess_->header.cont().size(); return ess_->header.cont().size();
@ -3957,11 +4023,12 @@ namespace nana
_m_ess().set_auto_draw(ad); _m_ess().set_auto_draw(ad);
} }
void listbox::append_header(nana::string text, unsigned width) listbox::size_type listbox::append_header(nana::string text, unsigned width)
{ {
auto & ess = _m_ess(); auto & ess = _m_ess();
ess.header.create(std::move(text), width); listbox::size_type index = ess.header.create(std::move(text), width);
ess.update(); ess.update();
return index;
} }
listbox& listbox::header_width(size_type pos, unsigned pixels) listbox& listbox::header_width(size_type pos, unsigned pixels)
@ -3971,6 +4038,13 @@ namespace nana
ess.update(); ess.update();
return *this; return *this;
} }
unsigned listbox::auto_width(size_type pos, unsigned max)
{
auto & ess = _m_ess();
unsigned max_w = ess.auto_width(pos, max);
ess.update();
return max_w;
}
unsigned listbox::header_width(size_type pos) const unsigned listbox::header_width(size_type pos) const
{ {