Merge branch 'qPCR4vir-hotfixes-1.0.2' into hotfixes-1.0.2
This commit is contained in:
commit
e31616e5dd
@ -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
|
||||
|
||||
## 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
|
||||
|
||||
There are two main branches with an infinite lifetime:
|
||||
|
||||
@ -163,9 +163,9 @@ namespace nana
|
||||
|
||||
typedef std::vector<index_pair> selection;
|
||||
|
||||
//struct essence_t
|
||||
//@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.
|
||||
/// struct essence_t
|
||||
///@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.
|
||||
struct essence_t;
|
||||
|
||||
struct category_t;
|
||||
@ -366,6 +366,7 @@ namespace nana
|
||||
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>);
|
||||
|
||||
size_type columns() const;
|
||||
@ -373,6 +374,9 @@ namespace nana
|
||||
cat_proxy& text(nana::string);
|
||||
nana::string text() const;
|
||||
|
||||
cat_proxy & select(bool);
|
||||
bool selected() const;
|
||||
|
||||
/// Behavior of a container
|
||||
void push_back(nana::string);
|
||||
|
||||
@ -473,16 +477,54 @@ namespace nana
|
||||
color_proxy header_grabbed{ static_cast<color_rgb>(0x8BD6F6)};
|
||||
color_proxy header_floated{ static_cast<color_rgb>(0xBABBBC)};
|
||||
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
|
||||
|
||||
/*! \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.
|
||||
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.
|
||||
The user can \a drag the header to \a reisize it or to \a reorganize it.
|
||||
By \a clicking on a header the list get \a reordered, first up, and then down alternatively.
|
||||
The user can \a drag the header to \a resize it or to \a reorganize it.
|
||||
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
|
||||
: 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, 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
|
||||
listbox& header_width(size_type pos, unsigned pixels);
|
||||
unsigned header_width(size_type pos) const;
|
||||
/// Appends a new column with a header text and the specified width at the end, and return it position
|
||||
size_type append_header(nana::string header_text, unsigned width = 120);
|
||||
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 at(size_type pos) const;
|
||||
|
||||
|
||||
@ -399,20 +399,19 @@ namespace nana
|
||||
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()));
|
||||
return cont_.back().index;
|
||||
}
|
||||
|
||||
void item_width(size_type pos, unsigned width)
|
||||
{
|
||||
if (pos >= cont_.size())
|
||||
return;
|
||||
|
||||
for(auto & m : cont_)
|
||||
{
|
||||
if(m.index == pos)
|
||||
{
|
||||
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_
|
||||
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;
|
||||
}
|
||||
bool categ_selected(size_type cat, bool sel);
|
||||
|
||||
void reverse_categ_selected(size_type categ)
|
||||
{
|
||||
@ -1644,7 +1619,20 @@ namespace nana
|
||||
/// absolute position of the last displayed item
|
||||
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
|
||||
@ -1656,32 +1644,32 @@ namespace nana
|
||||
{
|
||||
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
|
||||
{
|
||||
if (!good(pos.cat))
|
||||
return false;
|
||||
return false; // cat out of range
|
||||
|
||||
if (pos.is_category())
|
||||
{
|
||||
item = pos;
|
||||
if (0 == pos.cat)
|
||||
item.item = 0;
|
||||
|
||||
item = pos; // return the cat self
|
||||
if (0 == pos.cat) // but for cat 0 return first item
|
||||
item.item = 0; // let check this is good
|
||||
else
|
||||
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())
|
||||
{
|
||||
item = pos;
|
||||
item = pos; // good item, return it
|
||||
return true;
|
||||
}
|
||||
|
||||
if (++i == list_.end())
|
||||
if (++i == list_.end()) // item out of range and no more cat
|
||||
return false;
|
||||
|
||||
item.cat = pos.cat + 1;
|
||||
item.cat = pos.cat + 1; // select the next cat
|
||||
item.item = npos;
|
||||
return true;
|
||||
}
|
||||
@ -1689,7 +1677,7 @@ namespace nana
|
||||
///Translate relative position (position in display) into absolute position (original data order)
|
||||
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 ;
|
||||
|
||||
auto & catobj = *_m_at(display_pos.cat);
|
||||
@ -1739,13 +1727,12 @@ namespace nana
|
||||
return true;
|
||||
}
|
||||
|
||||
if(list_.size() <= from.cat) return false;
|
||||
|
||||
if(from.is_category())
|
||||
{
|
||||
// this is a category, so...
|
||||
// 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.
|
||||
// we can not select, navigate or highlight begining from a cat?
|
||||
--offs;
|
||||
from.item = 0;
|
||||
}
|
||||
@ -1754,7 +1741,7 @@ namespace nana
|
||||
|
||||
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 )
|
||||
{
|
||||
item = from;
|
||||
@ -1763,14 +1750,15 @@ namespace nana
|
||||
}
|
||||
else
|
||||
{
|
||||
offs -= item_left_in_this_cat ;
|
||||
offs -= (item_left_in_this_cat+1) ;
|
||||
item = from;
|
||||
item.item += item_left_in_this_cat ;
|
||||
item.item += item_left_in_this_cat ;// select the last item
|
||||
}
|
||||
}
|
||||
|
||||
++from.cat;
|
||||
++icat;
|
||||
|
||||
for(; icat != list_.end(); ++icat, ++from.cat)
|
||||
{
|
||||
item.cat = from.cat;
|
||||
@ -2195,7 +2183,7 @@ namespace nana
|
||||
}
|
||||
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;
|
||||
if(checkable)
|
||||
{
|
||||
@ -2316,6 +2304,28 @@ namespace nana
|
||||
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:
|
||||
void _m_answer_scroll(const arg_mouse& arg)
|
||||
{
|
||||
@ -2471,6 +2481,22 @@ namespace nana
|
||||
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
|
||||
{
|
||||
@ -2903,7 +2929,7 @@ namespace nana
|
||||
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 ?)
|
||||
{
|
||||
ext_w += 18;
|
||||
@ -3302,6 +3328,14 @@ namespace nana
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -3370,21 +3404,35 @@ namespace nana
|
||||
if (! scrl.make_page_scroll(!up))
|
||||
return;
|
||||
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()};
|
||||
if (!up)
|
||||
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;
|
||||
}
|
||||
case keyboard::os_home:
|
||||
{
|
||||
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 ();
|
||||
break;
|
||||
}
|
||||
case keyboard::os_end:
|
||||
essence_->lister.select_for_all(false);
|
||||
item_proxy::from_display(essence_, essence_->lister.last()).select(true);
|
||||
@ -3436,7 +3484,7 @@ namespace nana
|
||||
{
|
||||
auto i = ess_->lister.cat_container().begin();
|
||||
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
|
||||
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
|
||||
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
|
||||
{
|
||||
return ess_->header.cont().size();
|
||||
@ -3957,11 +4023,12 @@ namespace nana
|
||||
_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();
|
||||
ess.header.create(std::move(text), width);
|
||||
listbox::size_type index = ess.header.create(std::move(text), width);
|
||||
ess.update();
|
||||
return index;
|
||||
}
|
||||
|
||||
listbox& listbox::header_width(size_type pos, unsigned pixels)
|
||||
@ -3971,6 +4038,13 @@ namespace nana
|
||||
ess.update();
|
||||
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
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user