Merge branch 'feature-keyboard-accelerator' into develop

This commit is contained in:
Jinhao
2018-03-08 15:35:30 +08:00
27 changed files with 489 additions and 141 deletions

View File

@@ -379,7 +379,7 @@ namespace nana{ namespace drawerbase
}//end namespace drawerbase
//button
//@brief: Defaine a button widget and it provides the interfaces to be operational
//@brief: Define a button widget and it provides the interfaces to be operational
button::button(){}
button::button(window wd, bool visible)

View File

@@ -1,6 +1,6 @@
/*
* A Form Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,6 +10,7 @@
*/
#include <nana/gui/widgets/form.hpp>
#include <nana/gui/detail/bedrock.hpp>
namespace nana
{
@@ -94,6 +95,11 @@ namespace nana
{
API::wait_for(handle());
}
void form::keyboard_accelerator(const accel_key& key, const std::function<void()>& fn)
{
nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn);
}
//end class form
//class nested_form

View File

@@ -208,8 +208,8 @@ namespace nana{
outter[field_title] << impl_->caption;
outter.collocate();
impl_->caption.transparent(true);
color pbg = API::bgcolor(this->parent());
impl_->caption.bgcolor(pbg.blend(colors::black, 0.025));
this->bgcolor(pbg.blend(colors::black, 0.05));
@@ -222,10 +222,27 @@ namespace nana{
auto gap_px = impl_->gap - 1;
graph.rectangle(true, API::bgcolor(this->parent()));
graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2),
nana::size(graph.width() - 2 * gap_px, graph.height() - impl_->caption_dimension.height / 2 - gap_px)
auto const top_round_line = static_cast<int>(impl_->caption_dimension.height) / 2;
graph.round_rectangle(rectangle(point(gap_px, top_round_line),
nana::size(graph.width() - 2 * gap_px, graph.height() - top_round_line - gap_px)
),
3, 3, colors::gray_border, true, this->bgcolor());
auto opt_r = API::window_rectangle(impl_->caption);
if (opt_r)
{
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width, static_cast<unsigned>(top_round_line - opt_r->y) } };
grad_r.y += top_round_line*2 / 3;
grad_r.x -= 2;
grad_r.width += 4;
graph.gradual_rectangle(grad_r,
API::bgcolor(this->parent()), this->bgcolor(), true
);
}
});
}

View File

@@ -1,7 +1,7 @@
/*
* A List Box Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -1273,6 +1273,7 @@ namespace nana
}
//Backward
n = -n;
dpos = pos;
if (good(dpos.cat))
{
@@ -1519,8 +1520,6 @@ namespace nana
template<typename Pred>
std::vector<std::pair<index_pair, bool>> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool deselect_others, Pred pred)
{
const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{});
if (to_dpl.empty())
{
if (fr_abs.empty())
@@ -1533,6 +1532,11 @@ namespace nana
if (fr_dpl > to_dpl)
std::swap(fr_dpl, to_dpl);
if (to_dpl.is_category() && this->size_item(to_dpl.cat) > 0)
to_dpl.item = this->size_item(to_dpl.cat) - 1;
const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{});
const auto begin = fr_dpl;
const auto last = to_dpl;
@@ -1586,7 +1590,7 @@ namespace nana
return pairs;
}
bool select_for_all(bool sel, const index_pair& except = index_pair{npos, npos})
bool select_for_all(bool sel, const index_pair& except_abs = index_pair{npos, npos})
{
bool changed = false;
index_pair pos;
@@ -1595,7 +1599,7 @@ namespace nana
pos.item = 0;
for(auto & m : cat.items)
{
if (except != pos)
if (except_abs != pos)
{
if (m.flags.selected != sel)
{
@@ -1618,7 +1622,7 @@ namespace nana
}
/// return absolute positions, no relative to display
index_pairs pick_items(bool for_selection) const
index_pairs pick_items(bool for_selection, bool find_first = false) const
{
index_pairs results;
index_pair id;
@@ -1629,7 +1633,11 @@ namespace nana
for (auto & m : cat.items)
{
if (for_selection ? m.flags.selected : m.flags.checked)
{
results.push_back(id); // absolute positions, no relative to display
if (find_first)
return results;
}
++id.item;
}
++id.cat;
@@ -1978,6 +1986,15 @@ namespace nana
};
}
bool cs_status(index_pair abs_pos, bool for_selection) const
{
if (abs_pos.is_category())
return lister.cat_status(abs_pos.cat, for_selection);
auto & flags = lister.get(abs_pos.cat)->items.at(abs_pos.item).flags;
return (for_selection ? flags.selected : flags.checked);
}
void resize_disp_area()
{
auto head_px = this->header_visible_px();
@@ -3416,6 +3433,8 @@ namespace nana
rect.y - static_cast<int>(origin.y % item_height_px)
};
essence_->inline_buffered_table.swap(essence_->inline_table);
// The first display is empty when the listbox is empty.
if (!first_disp.empty())
{
@@ -3438,8 +3457,6 @@ namespace nana
auto idx = first_disp;
essence_->inline_buffered_table.swap(essence_->inline_table);
for (auto & cat : lister.cat_container())
for (auto & ind : cat.indicators)
{
@@ -3509,10 +3526,10 @@ namespace nana
++idx.item;
}
}
essence_->inline_buffered_table.clear();
}
essence_->inline_buffered_table.clear();
if (item_coord.y < rect.bottom())
{
rectangle bground_r{ rect.x, item_coord.y, rect.width, static_cast<unsigned>(rect.bottom() - item_coord.y) };
@@ -4117,17 +4134,16 @@ namespace nana
essence_->content_view->sync(false);
}
bool sel = true;
bool new_selected_status = true;
//no single selected
if (!lister.single_status(true))
if (!lister.single_status(true)) //multiply selection enabled
{
if (arg.shift)
{
//Set the first item as the begin of selected item if there
//is not a latest selected item.(#154 reported by RenaudAlpes)
if (lister.latest_selected_abs.empty() || lister.latest_selected_abs.is_category())
lister.latest_selected_abs.set_both(0);
if (lister.latest_selected_abs.empty())
lister.latest_selected_abs = lister.first();
auto before = lister.latest_selected_abs;
@@ -4141,7 +4157,7 @@ namespace nana
else if (arg.ctrl)
{
essence_->mouse_selection.reverse_selection = true;
sel = !item_proxy(essence_, abs_item_pos).selected();
new_selected_status = !essence_->cs_status(abs_item_pos, true);
}
else
{
@@ -4150,12 +4166,12 @@ namespace nana
//Unselects all selected items if the current item is not selected before selecting.
auto selected = lister.pick_items(true);
if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos))
lister.select_for_all(false, item_pos);
lister.select_for_all(false, abs_item_pos);
}
else
{
//Unselects all selected items except current item if right button clicked.
lister.select_for_all(false, item_pos); //cancel all selections
lister.select_for_all(false, abs_item_pos); //cancel all selections
}
}
}
@@ -4164,14 +4180,14 @@ namespace nana
//Clicking on a category is ignored when single selection is enabled.
//Fixed by Greentwip(issue #121)
if (item_ptr)
sel = !item_proxy(essence_, abs_item_pos).selected();
new_selected_status = !item_proxy(essence_, abs_item_pos).selected();
}
if(item_ptr)
{
if (item_ptr->flags.selected != sel)
if (item_ptr->flags.selected != new_selected_status)
{
if (sel)
if (new_selected_status)
{
//Deselects the previously selected item.
lister.cancel_others_if_single_enabled(true, abs_item_pos);
@@ -4180,13 +4196,15 @@ namespace nana
else if (essence_->lister.latest_selected_abs == abs_item_pos)
essence_->lister.latest_selected_abs.set_both(npos);
item_ptr->flags.selected = sel;
item_ptr->flags.selected = new_selected_status;
lister.emit_cs(abs_item_pos, true);
}
}
else
{
lister.cat_status(item_pos.cat, true, true);
//A category was clicked. Sets all child items to be selected only if multiply selection is enabled.
if(!lister.single_status(true))
lister.cat_status(item_pos.cat, true, true);
}
}
else
@@ -4336,8 +4354,9 @@ namespace nana
void trigger::key_press(graph_reference graph, const arg_keyboard& arg)
{
auto & list = essence_->lister;
// Exit if list is empty
if (essence_->lister.first().empty())
if (list.first().empty())
return;
bool upward = false;
@@ -4347,12 +4366,12 @@ namespace nana
case keyboard::os_arrow_up:
upward = true;
case keyboard::os_arrow_down:
essence_->lister.move_select(upward, !arg.shift, true);
list.move_select(upward, !arg.shift, true);
break;
case L' ':
{
index_pairs s;
bool ck = ! essence_->lister.item_selected_all_checked(s);
bool ck = ! list.item_selected_all_checked(s);
for(auto i : s)
item_proxy(essence_, i).check(ck);
}
@@ -4361,30 +4380,69 @@ namespace nana
upward = true;
case keyboard::os_pagedown:
{
//Turns page, then returns if no change occurs
if (!essence_->content_view->turn_page(!upward, false))
return;
auto const item_px = essence_->item_height();
auto picked_items = list.pick_items(true, true);
index_pair init_idx = (picked_items.empty() ? list.first() : picked_items[0]);
essence_->lister.select_for_all(false);
auto idx = essence_->first_display();
//Get the pixels between the init item and top edge or bottom edge
auto logic_top = static_cast<int>(list.distance(list.first(), init_idx) * item_px);
if (!upward)
idx = essence_->lister.advance(idx, static_cast<int>(essence_->count_of_exposed(false)) - 1);
auto const screen_top = essence_->content_view->origin().y;
auto const screen_bottom = screen_top + essence_->content_view->view_area().height;
index_pair target_idx;
if (!idx.is_category())
item_proxy::from_display(essence_, idx).select(true);
else if (!essence_->lister.single_status(true)) //not selected
essence_->lister.cat_status(idx.cat, true, true);
//Check if it scrolls in current screen window
//condition: top of target item is not less than top edge of content view and
//the bottom of target item is not greater than bottom edge of content view.
if ((screen_top + item_px <= logic_top) && (logic_top + item_px + item_px <= screen_bottom))
{
int offset = (static_cast<int>(upward ? screen_top : screen_bottom - item_px) - logic_top) / static_cast<int>(item_px);
target_idx = list.advance(init_idx, offset);
}
else
{
//turn page
auto page_item_count = (std::max)(1, static_cast<int>(essence_->count_of_exposed(false)));
break;
auto origin = essence_->content_view->origin();
if (upward)
{
target_idx = list.advance(init_idx, -page_item_count);
if (target_idx.empty())
target_idx = list.first();
origin.y = list.distance(list.first(), target_idx) * item_px;
}
else
{
target_idx = list.advance(init_idx, page_item_count);
if (target_idx.empty())
target_idx = list.last();
origin.y = list.distance(list.first(), target_idx) * item_px + item_px;
if (origin.y >= (screen_bottom - screen_top))
origin.y -= (screen_bottom - screen_top);
else
origin.y = 0;
}
essence_->content_view->move_origin(origin - essence_->content_view->origin());
}
if (!target_idx.is_category())
item_proxy::from_display(essence_, target_idx).select(true);
else if (!list.single_status(true)) //not selected
list.cat_status(target_idx.cat, true, true);
}
break;
case keyboard::os_home:
case keyboard::os_end:
{
essence_->lister.select_for_all(false);
list.select_for_all(false);
auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.last());
auto pos = (keyboard::os_home == arg.key ? list.first() : list.last());
if (!pos.empty())
{
//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.
@@ -4393,9 +4451,9 @@ namespace nana
{
if (keyboard::os_home == arg.key)
{
while (0 == essence_->lister.size_item(pos.cat))
while (0 == list.size_item(pos.cat))
{
if (++pos.cat >= essence_->lister.cat_container().size())
if (++pos.cat >= list.cat_container().size())
{
pos = index_pair{ npos, npos };
break;
@@ -4404,7 +4462,7 @@ namespace nana
}
else
{
while (0 == essence_->lister.size_item(pos.cat))
while (0 == list.size_item(pos.cat))
{
if (pos.cat-- == 0)
{
@@ -4416,7 +4474,7 @@ namespace nana
if (!pos.empty())
{
if (essence_->lister.expand(pos.cat))
if (list.expand(pos.cat))
pos.item = 0;
}
}
@@ -4425,8 +4483,8 @@ namespace nana
{
if (pos.is_category())
{
if (!essence_->lister.single_status(true)) //multiple selection is not enabled
essence_->lister.cat_status(pos.cat, true, true);
if (!list.single_status(true)) //multiple selection is not enabled
list.cat_status(pos.cat, true, true);
}
else
item_proxy::from_display(essence_, pos).select(true);
@@ -4662,12 +4720,12 @@ namespace nana
bool item_proxy::operator==(const std::string& s) const
{
return (text(pos_.item) == s);
return (text(0) == s);
}
bool item_proxy::operator==(const std::wstring& s) const
{
return (text(pos_.item) == to_utf8(s));
return (text(0) == to_utf8(s));
}
item_proxy & item_proxy::operator=(const item_proxy& rhs)
@@ -5158,7 +5216,8 @@ namespace nana
cat_->make_sort_order();
ess_->lister.sort();
ess_->update(true);
//Don't ignore the auto-draw flag for performance enhancement.
ess_->update();
}
}
//end class cat_proxy

View File

@@ -1,6 +1,6 @@
/*
* A Progress Indicator Implementation
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -96,7 +96,11 @@ namespace nana
{
if (widget_)
{
auto value_px = (widget_->size().width - border_px * 2) * value_ / max_;
auto value_px = (widget_->size().width - border_px * 2);
//avoid overflow
if (value_ < max_)
value_px = static_cast<unsigned>(value_px * (double(value_) / double(max_)));
if (value_px != value_px_)
{

View File

@@ -1,7 +1,7 @@
/*
* A Scroll Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@@ -20,9 +20,15 @@ namespace nana
namespace scroll
{
//struct metrics_type
metrics_type::metrics_type()
:peak(1), range(1), step(1), value(0),
what(buttons::none), pressed(false), scroll_length(0), scroll_pos(0)
metrics_type::metrics_type():
peak(1),
range(1),
step(1),
value(0),
what(buttons::none),
pressed(false),
scroll_length(0),
scroll_pos(0)
{}
//end struct metrics_type