fix some bugs of listbox box selection

This commit is contained in:
Jinhao 2017-06-13 23:25:58 +08:00
parent 40cfe5f404
commit 8044cb0b34

View File

@ -1517,22 +1517,20 @@ namespace nana
if (to_dpl.is_category()) if (to_dpl.is_category())
{ {
auto size = this->size_item(to_dpl.cat); //Search backward until a last item of a category is found.
if (0 == size) while (true)
{ {
while (to_dpl.cat > 0) auto msize = this->size_item(to_dpl.cat);
if (0 != msize)
{ {
size = this->size_item(--to_dpl.cat); to_dpl.item = msize - 1;
if (size > 0)
{
to_dpl.item = size - 1;
break; break;
} }
}
} if (fr_dpl.cat == to_dpl.cat)
else if (size > 0) break;
{
to_dpl.item = size - 1; --(to_dpl.cat);
} }
} }
@ -1546,7 +1544,7 @@ namespace nana
//pair second: indicates whether the index is selected before selection. //pair second: indicates whether the index is selected before selection.
std::vector<std::pair<index_pair, bool>> pairs; std::vector<std::pair<index_pair, bool>> pairs;
for (; fr_dpl != to_dpl; fr_dpl = advance(fr_dpl, 1)) for (; !(fr_dpl > to_dpl); fr_dpl = advance(fr_dpl, 1)) //fr_dpl <= to_dpl
{ {
if (fr_dpl.is_category()) if (fr_dpl.is_category())
{ {
@ -1578,33 +1576,6 @@ namespace nana
} }
} }
if (to_dpl.is_category())
{
if (!expand(to_dpl.cat))
{
auto size = size_item(to_dpl.cat);
for (std::size_t i = 0; i < size; ++i)
{
index_pair abs_pos{ fr_dpl.cat, i };
item_proxy m{ ess_, abs_pos };
pairs.emplace_back(abs_pos, m.selected());
if (pred(abs_pos))
m.select(true);
}
}
}
else
{
auto abs_pos = index_cast(to_dpl, true); //convert display position to absolute position
item_proxy m(ess_, abs_pos);
pairs.emplace_back(abs_pos, m.selected());
if (pred(abs_pos))
m.select(true);
}
if (unselect_others) if (unselect_others)
{ {
//Unselects the already selected which is out of range [begin, last] //Unselects the already selected which is out of range [begin, last]
@ -1638,9 +1609,9 @@ namespace nana
this->emit_cs(pos, true); this->emit_cs(pos, true);
if (m.flags.selected) if (m.flags.selected)
last_selected_abs = pos; latest_selected_abs = pos;
else if (last_selected_abs == pos) else if (latest_selected_abs == pos)
last_selected_abs.set_both(npos); //make empty latest_selected_abs.set_both(npos); //make empty
} }
} }
++pos.item; ++pos.item;
@ -1879,8 +1850,13 @@ namespace nana
else else
i.item = npos; i.item = npos;
} }
else if (i.item) else
{
if (i.item)
--i.item; --i.item;
else
return index_pair{ npos, npos };
}
return i; return i;
} }
@ -1888,9 +1864,14 @@ namespace nana
/// can be used as the absolute position of the first absolute item, or as the display pos of the first displayed item /// 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 noexcept index_pair first() const noexcept
{ {
index_pair fst{0,npos}; auto i = categories_.cbegin();
good_item(fst,fst); if (i->items.size())
return fst; return index_pair{ 0, 0 };
if (categories_.size() > 1)
return index_pair{ 1, npos };
return index_pair{ npos, npos };
} }
bool good(size_type cat) const noexcept bool good(size_type cat) const noexcept
@ -1903,36 +1884,6 @@ namespace nana
return ((pos.cat < categories_.size()) && (pos.item < size_item(pos.cat))); return ((pos.cat < categories_.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(const index_pair& pos, index_pair& item) const noexcept
{
if (!good(pos.cat))
return false; // cat out of range
if (pos.is_category())
{
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 = get(pos.cat); // pos is not a cat and i point to it cat
if (pos.item < i->items.size())
{
item = pos; // good item, return it
return true;
}
if (++i == categories_.cend()) // item out of range and no more cat
return false;
item.cat = pos.cat + 1; // select the next cat
item.item = npos;
return true;
}
/// categories iterator /// categories iterator
container::iterator get(size_type pos) container::iterator get(size_type pos)
{ {
@ -1952,7 +1903,7 @@ namespace nana
return i; return i;
} }
public: public:
index_pair last_selected_abs; index_pair latest_selected_abs; //Stands for the latest selected item that selected by last operation. Invalid if it is empty.
private: private:
essence * ess_{nullptr}; essence * ess_{nullptr};
nana::listbox * widget_{nullptr}; nana::listbox * widget_{nullptr};
@ -2932,7 +2883,7 @@ namespace nana
void es_lister::move_select(bool upwards, bool unselect_previous, bool /*trace_selected*/) noexcept void es_lister::move_select(bool upwards, bool unselect_previous, bool /*trace_selected*/) noexcept
{ {
auto next_selected_dpl = index_cast_noexcpt(last_selected_abs, false); //convert absolute position to display position auto next_selected_dpl = index_cast_noexcpt(latest_selected_abs, false); //convert absolute position to display position
if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat
{ {
@ -3053,8 +3004,8 @@ namespace nana
for (item_proxy &it : cpx) for (item_proxy &it : cpx)
it.select(value); it.select(value);
last_selected_abs.cat = pos; latest_selected_abs.cat = pos;
last_selected_abs.item = npos; latest_selected_abs.item = npos;
return true; return true;
} }
@ -4124,18 +4075,18 @@ namespace nana
if (arg.shift) if (arg.shift)
{ {
//Set the first item as the begin of selected item if there //Set the first item as the begin of selected item if there
//is not a last selected item.(#154 reported by RenaudAlpes) //is not a latest selected item.(#154 reported by RenaudAlpes)
if (lister.last_selected_abs.empty() || lister.last_selected_abs.is_category()) if (lister.latest_selected_abs.empty() || lister.latest_selected_abs.is_category())
lister.last_selected_abs.set_both(0); lister.latest_selected_abs.set_both(0);
auto before = lister.last_selected_abs; auto before = lister.latest_selected_abs;
lister.select_display_range_if(lister.last_selected_abs, item_pos, true, [](const index_pair&) lister.select_display_range_if(lister.latest_selected_abs, item_pos, true, [](const index_pair&)
{ {
return true; return true;
}); });
lister.last_selected_abs = before; lister.latest_selected_abs = before;
} }
else if (arg.ctrl) else if (arg.ctrl)
{ {
@ -4176,10 +4127,10 @@ namespace nana
if (item_ptr->flags.selected) if (item_ptr->flags.selected)
{ {
lister.cancel_others_if_single_enabled(true, abs_item_pos); lister.cancel_others_if_single_enabled(true, abs_item_pos);
essence_->lister.last_selected_abs = abs_item_pos; essence_->lister.latest_selected_abs = abs_item_pos;
} }
else if (essence_->lister.last_selected_abs == abs_item_pos) else if (essence_->lister.latest_selected_abs == abs_item_pos)
essence_->lister.last_selected_abs.set_both(npos); essence_->lister.latest_selected_abs.set_both(npos);
} }
} }
else else
@ -4350,17 +4301,18 @@ namespace nana
void trigger::key_press(graph_reference graph, const arg_keyboard& arg) void trigger::key_press(graph_reference graph, const arg_keyboard& arg)
{ {
bool up = false; // Exit if list is empty
if (essence_->lister.first().empty())
if (essence_->lister.cat_container().size() == 1 && essence_->lister.size_item(0)==0)
return; return;
bool upward = false;
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_up: case keyboard::os_arrow_up:
up = true; upward = true;
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
essence_->lister.move_select(up, !arg.shift, true); essence_->lister.move_select(upward, !arg.shift, true);
break; break;
case L' ': case L' ':
{ {
@ -4371,18 +4323,18 @@ namespace nana
} }
break; break;
case keyboard::os_pageup : case keyboard::os_pageup :
up = true; upward = true;
case keyboard::os_pagedown: case keyboard::os_pagedown:
{ {
//Turns page, then returns if no change occurs //Turns page, then returns if no change occurs
if (!essence_->content_view->turn_page(!up, false)) if (!essence_->content_view->turn_page(!upward, false))
return; return;
essence_->lister.select_for_all(false); essence_->lister.select_for_all(false);
auto idx = essence_->first_display(); auto idx = essence_->first_display();
if (!up) if (!upward)
idx = essence_->lister.advance(idx, static_cast<int>(essence_->count_of_exposed(false)) - 1); idx = essence_->lister.advance(idx, static_cast<int>(essence_->count_of_exposed(false)) - 1);
if (!idx.is_category()) if (!idx.is_category())
@ -4393,20 +4345,59 @@ namespace nana
break; break;
} }
case keyboard::os_home: case keyboard::os_home:
case keyboard::os_end:
{ {
essence_->lister.select_for_all(false); essence_->lister.select_for_all(false);
index_pair frst{essence_->lister.first()}; auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.last());
if (! frst.is_category()) if (!pos.empty())
item_proxy::from_display(essence_, frst).select(true); {
else if (!essence_->lister.single_status(true)) //not selected //When the pos indicates an empty category, then search forwards/backwards(depending on arg.key whether it is Home or End) for a non empty category.
essence_->lister.cat_status(frst.cat, true, true); //When a non-empty category is found, assign the pos to the first/last item of the category if the category is expanded.
if (pos.is_category())
{
if (keyboard::os_home == arg.key)
{
while (0 == essence_->lister.size_item(pos.cat))
{
if (++pos.cat >= essence_->lister.cat_container().size())
{
pos = index_pair{ npos, npos };
break; break;
} }
case keyboard::os_end: }
essence_->lister.select_for_all(false); }
item_proxy::from_display(essence_, essence_->lister.last()).select(true); else
{
while (0 == essence_->lister.size_item(pos.cat))
{
if (pos.cat-- == 0)
{
pos = index_pair{ npos, npos };
break;
}
}
}
if (!pos.empty())
{
if (essence_->lister.expand(pos.cat))
pos.item = 0;
}
}
if (!pos.empty())
{
if (pos.is_category())
{
if (!essence_->lister.single_status(true)) //multiple selection is not enabled
essence_->lister.cat_status(pos.cat, true, true);
}
else
item_proxy::from_display(essence_, pos).select(true);
}
}
}
break; break;
default: default:
return; return;
@ -4531,10 +4522,10 @@ namespace nana
if (m.flags.selected) if (m.flags.selected)
{ {
ess_->lister.cancel_others_if_single_enabled(true, pos_); //Cancel all selections except pos_ if single_selection is enabled. ess_->lister.cancel_others_if_single_enabled(true, pos_); //Cancel all selections except pos_ if single_selection is enabled.
ess_->lister.last_selected_abs = pos_; ess_->lister.latest_selected_abs = pos_;
} }
else if (ess_->lister.last_selected_abs == pos_) else if (ess_->lister.latest_selected_abs == pos_)
ess_->lister.last_selected_abs.set_both(npos); ess_->lister.latest_selected_abs.set_both(npos);
if (scroll_view) if (scroll_view)
{ {
@ -4808,7 +4799,7 @@ namespace nana
for (item_proxy &it : *this ) for (item_proxy &it : *this )
it.select(sel); it.select(sel);
ess_->lister.last_selected_abs = index_pair {this->pos_, npos}; ess_->lister.latest_selected_abs = index_pair {this->pos_, npos};
return *this; return *this;
} }
@ -5432,7 +5423,6 @@ namespace nana
{ {
auto & ess = _m_ess(); auto & ess = _m_ess();
ess.lister.erase(); ess.lister.erase();
//ess.first_display(ess.lister.first());
ess.calc_content_size(); ess.calc_content_size();
ess.update(); ess.update();
} }