fix issue that reverse box selection works incorrectly

new bug from develop-1.7
This commit is contained in:
Jinhao 2019-01-27 06:14:21 +08:00
parent e057724f98
commit 3e9b08c0cc

View File

@ -2011,6 +2011,8 @@ namespace nana
{ {
bool started{ false }; bool started{ false };
bool reverse_selection{ false }; bool reverse_selection{ false };
bool scroll_direction;
bool deselect_when_start_to_move;
point screen_pos; point screen_pos;
point begin_position; ///< Logical position to the point begin_position; ///< Logical position to the
@ -2018,9 +2020,18 @@ namespace nana
index_pairs already_selected; index_pairs already_selected;
index_pairs selections; index_pairs selections;
bool scroll_direction;
unsigned scroll_step{ 1 }; unsigned scroll_step{ 1 };
unsigned mouse_move_timestamp{ 0 }; unsigned mouse_move_timestamp{ 0 };
bool is_already_selected(const index_pair& abs_pos) const noexcept
{
return (already_selected.cend() != std::find(already_selected.cbegin(), already_selected.cend(), abs_pos));
}
bool is_selected(const index_pair& abs_pos) const noexcept
{
return (selections.cend() != std::find(selections.cbegin(), selections.cend(), abs_pos));
}
}mouse_selection; }mouse_selection;
@ -2118,6 +2129,7 @@ namespace nana
mouse_selection.started = true; mouse_selection.started = true;
mouse_selection.begin_position = logic_pos; mouse_selection.begin_position = logic_pos;
mouse_selection.end_position = logic_pos; mouse_selection.end_position = logic_pos;
mouse_selection.deselect_when_start_to_move = true;
if (arg.ctrl || arg.shift) if (arg.ctrl || arg.shift)
{ {
@ -2133,6 +2145,17 @@ namespace nana
if (!mouse_selection.started) if (!mouse_selection.started)
return; return;
// When the button is pressed and start to move the mouse, the listbox should deselect all items.
// But when ctrl is clicked
if (mouse_selection.deselect_when_start_to_move)
{
mouse_selection.deselect_when_start_to_move = false;
if (mouse_selection.already_selected.empty())
lister.select_for_all(false);
mouse_selection.selections.clear();
}
mouse_selection.screen_pos = screen_pos; mouse_selection.screen_pos = screen_pos;
auto logic_pos = coordinate_cast(screen_pos, true); auto logic_pos = coordinate_cast(screen_pos, true);
@ -2148,7 +2171,7 @@ namespace nana
mouse_selection.end_position = logic_pos; mouse_selection.end_position = logic_pos;
bool cancel_selections = true; std::vector<std::pair<index_pair, bool>> selections;
auto content_x = coordinate_cast({ columns_range().first, 0 }, true).x; auto content_x = coordinate_cast({ columns_range().first, 0 }, true).x;
if ((std::max)(mouse_selection.end_position.x, mouse_selection.begin_position.x) >= content_x && if ((std::max)(mouse_selection.end_position.x, mouse_selection.begin_position.x) >= content_x &&
@ -2159,18 +2182,18 @@ namespace nana
auto begin = lister.advance(lister.first(), begin_off); auto begin = lister.advance(lister.first(), begin_off);
if (!begin.empty()) if (!begin.empty())
{ {
std::vector<std::pair<index_pair, bool>> selections;
if ((mouse_selection.end_position.y < 0) || (lister.distance(lister.first(), begin) == begin_off)) if ((mouse_selection.end_position.y < 0) || (lister.distance(lister.first(), begin) == begin_off))
{ {
//The range [begin_off, last_off] is a range of box selection //The range [begin_off, last_off] is a range of box selection
auto last_off = (std::max)(mouse_selection.begin_position.y, mouse_selection.end_position.y) / item_height(); auto last_off = (std::max)(mouse_selection.begin_position.y, mouse_selection.end_position.y) / item_height();
auto last = lister.advance(lister.first(), last_off); auto last = lister.advance(lister.first(), last_off);
//Tries to select the items in the box, then returns the items with their previous selected states
selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) { selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) {
if (this->mouse_selection.reverse_selection) if (mouse_selection.reverse_selection)
{ {
if (mouse_selection.already_selected.cend() != std::find(mouse_selection.already_selected.cbegin(), mouse_selection.already_selected.cend(), abs_pos)) //Deselects the items in the box which has been already selected
if(mouse_selection.is_already_selected(abs_pos))
{ {
item_proxy{ this, abs_pos }.select(false); item_proxy{ this, abs_pos }.select(false);
return false; return false;
@ -2181,21 +2204,21 @@ namespace nana
for (auto & pair : selections) for (auto & pair : selections)
{ {
//Continue if the previous state is selected. It indicates the item now is not selected.
if (pair.second) if (pair.second)
continue; continue;
if (mouse_selection.selections.cend() == //Add the item to selections container.
std::find(mouse_selection.selections.cbegin(), mouse_selection.selections.cend(), pair.first)) if(!mouse_selection.is_selected(pair.first))
{
mouse_selection.selections.push_back(pair.first); mouse_selection.selections.push_back(pair.first);
}
} }
//Deselects the items which are in mouse_selection.selections but not in selections.
//Eq to mouse_selection.selections = selections
#ifdef _MSC_VER #ifdef _MSC_VER
for (auto i = mouse_selection.selections.cbegin(); i != mouse_selection.selections.cend();) for (auto i = mouse_selection.selections.cbegin(); i != mouse_selection.selections.cend();)
#else #else
for(auto i = mouse_selection.selections.begin(); i != mouse_selection.selections.end();) for(auto i = mouse_selection.selections.begin(); i != mouse_selection.selections.end();)
#endif #endif
{ {
auto & selpos = *i; auto & selpos = *i;
@ -2209,30 +2232,45 @@ namespace nana
else else
++i; ++i;
} }
cancel_selections = false;
} }
} }
} }
if (cancel_selections) //Restores an already selected item if it is not in selections.
for (auto& abs_pos : mouse_selection.already_selected)
{ {
if (!mouse_selection.already_selected.empty()) if (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), [abs_pos](const std::pair<index_pair, bool>& rhs) {
return (abs_pos == rhs.first);
}))
{ {
for (auto & pos : mouse_selection.selections) item_proxy m{ this, abs_pos };
item_proxy(this, pos).select(false); if (!m.selected())
//Don't restore the already selections if it is reverse selection(pressing shift). Behaves like Windows Explorer.
if (!mouse_selection.reverse_selection)
{ {
for (auto & abs_pos : mouse_selection.already_selected) m.select(true);
item_proxy(this, abs_pos).select(true); //Add the item to selections container.
if(!mouse_selection.is_selected(abs_pos))
mouse_selection.selections.push_back(abs_pos);
} }
} }
else }
lister.select_for_all(false);
mouse_selection.selections.clear(); //Deselects the item which is not in already_selected and selections but in mouse_selection.selections
for(auto i = mouse_selection.selections.cbegin(); i != mouse_selection.selections.cend();)
{
auto abs_pos = *i;
bool is_box_selected = (selections.cend() != std::find_if(selections.cbegin(), selections.cend(), [abs_pos](const std::pair<index_pair, bool>& rhs) {
return (abs_pos == rhs.first);
}));
if (is_box_selected || mouse_selection.is_already_selected(abs_pos))
{
++i;
continue;
}
item_proxy{ this, abs_pos }.select(false);
i = mouse_selection.selections.erase(i);
} }
} }
@ -4374,7 +4412,7 @@ namespace nana
if (arg.is_left_button() && (!lister.single_status(true))) if (arg.is_left_button() && (!lister.single_status(true)))
essence_->start_mouse_selection(arg); essence_->start_mouse_selection(arg);
//Deselection of all items is deferred to the mouse up event when ctrl or shift is not pressed //Deselecting all items is deferred to the mouse up event when ctrl or shift is not pressed
//Pressing ctrl or shift is to selects other items without deselecting current selections. //Pressing ctrl or shift is to selects other items without deselecting current selections.
if (!(arg.ctrl || arg.shift)) if (!(arg.ctrl || arg.shift))
{ {