Merge branch 'hotfix-1.4' into develop

This commit is contained in:
Jinhao
2016-09-24 09:58:44 +08:00
16 changed files with 349 additions and 145 deletions

View File

@@ -442,8 +442,6 @@ namespace nana
bool basic_window::set_events(const std::shared_ptr<general_events>& p)
{
if (annex.events_ptr)
return false;
annex.events_ptr = p;
return true;
}

View File

@@ -626,30 +626,38 @@ namespace detail
if(pressed_wd_space)
break;
msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd)
break;
if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5)
{
//The hovered window receives the message, unlike in Windows, no redirection is required.
nana::point mspos{xevent.xbutton.x, xevent.xbutton.y};
while(msgwnd)
auto evt_wd = msgwnd;
while(evt_wd)
{
if(msgwnd->annex.events_ptr->mouse_wheel.length() != 0)
if(evt_wd->annex.events_ptr->mouse_wheel.length() != 0)
{
mspos -= msgwnd->pos_root;
arg_wheel arg;
arg.which = arg_wheel::wheel::vertical;
assign_arg(arg, msgwnd, xevent);
brock.emit(event_code::mouse_wheel, msgwnd, arg, true, &context);
assign_arg(arg, evt_wd, xevent);
brock.emit(event_code::mouse_wheel, evt_wd, arg, true, &context);
break;
}
msgwnd = msgwnd->parent;
evt_wd = evt_wd->parent;
}
if(msgwnd && (nullptr == evt_wd))
{
arg_wheel arg;
arg.which = arg_wheel::wheel::vertical;
assign_arg(arg, msgwnd, xevent);
draw_invoker(&drawer::mouse_wheel, msgwnd, arg, &context);
wd_manager.do_lazy_refresh(msgwnd, false);
}
}
else
{
msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd)
break;
msgwnd->set_action(mouse_action::normal);
if(msgwnd->flags.enabled)
{

View File

@@ -1124,8 +1124,6 @@ namespace detail
if (evt_wd->annex.events_ptr->mouse_wheel.length() != 0)
{
def_window_proc = false;
nana::point mspos{ scr_pos.x, scr_pos.y };
wd_manager.calc_window_point(evt_wd, mspos);
arg_wheel arg;
arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical);
@@ -1138,9 +1136,6 @@ namespace detail
if (scrolled_wd && (nullptr == evt_wd))
{
nana::point mspos{ scr_pos.x, scr_pos.y };
wd_manager.calc_window_point(scrolled_wd, mspos);
arg_wheel arg;
arg.which = (WM_MOUSEHWHEEL == message ? arg_wheel::wheel::horizontal : arg_wheel::wheel::vertical);
assign_arg(arg, scrolled_wd, pmdec);

View File

@@ -1714,6 +1714,11 @@ namespace detail
wd->annex.caret_ptr = nullptr;
}
using effect_renderer = detail::edge_nimbus_renderer<basic_window>;
//remove the window from edge nimbus effect when it is destroying
effect_renderer::instance().erase(wd);
arg_destroy arg;
arg.window_handle = reinterpret_cast<window>(wd);
brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context());

View File

@@ -498,24 +498,26 @@ namespace nana
if(name.empty() || (name.front() == '.'))
continue;
auto fpath = i->path().native();
auto fattr = fs::status(fpath);
item_fs m;
m.name = name;
m.directory = fs::is_directory(fattr);
auto fattr = fs::status(path + m.name);
if(fattr.type() != fs::file_type::not_found && fattr.type() != fs::file_type::unknown)
{
m.bytes = fs::file_size(path + m.name);
m.directory = fs::is_directory(fattr);
fs_ext::modified_file_time(path + m.name, m.modified_time);
}
else
switch(fattr.type())
{
case fs::file_type::not_found:
case fs::file_type::unknown:
case fs::file_type::directory:
m.bytes = 0;
m.directory = fs::is_directory(*i);
fs_ext::modified_file_time(path + i->path().filename().native(), m.modified_time);
break;
default:
m.bytes = fs::file_size(fpath);
}
fs_ext::modified_file_time(fpath, m.modified_time);
file_container_.push_back(m);
if(m.directory)

View File

@@ -679,6 +679,16 @@ namespace nana
}
};
struct inline_pane
{
::nana::panel<false> pane_bottom; //pane for pane_widget
::nana::panel<false> pane_widget; //pane for placing user-define widget
std::unique_ptr<inline_notifier_interface> inline_ptr;
inline_indicator * indicator;
index_pair item_pos; //The item index of the inline widget
std::size_t column_pos;
};
class es_lister
{
public:
@@ -727,6 +737,40 @@ namespace nana
std::string to_string(const export_options& exp_opt) const;
std::vector<inline_pane*> get_inline_pane(const index_pair& item_pos)
{
std::vector<inline_pane*> panes;
for (auto p : active_panes_)
{
if (p && (p->item_pos == item_pos))
{
panes.emplace_back(p);
}
}
return panes;
}
void emit_checked(index_pair pos)
{
item_proxy i(ess_, pos);
arg_listbox arg{ i };
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
auto panes = get_inline_pane(pos);
for (auto p : panes)
p->inline_ptr->notify_status(inline_widget_status::checking, i.checked());
}
void emit_selected(index_pair pos)
{
item_proxy i(ess_, pos);
arg_listbox arg{ i };
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
auto panes = get_inline_pane(pos);
for (auto p : panes)
p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected());
}
// Definition is provided after struct essence
unsigned column_content_pixels(size_type pos) const;
@@ -1122,6 +1166,14 @@ namespace nana
return get(pos.cat)->items.at(index);
}
void append_active_panes(inline_pane* p)
{
if (nullptr == p)
active_panes_.clear();
else
active_panes_.push_back(p);
}
// Removes all items of a specified category
// It throws when the category is out of range or has an immutable model.
void clear(size_type cat)
@@ -1453,9 +1505,7 @@ namespace nana
if(m.flags.checked != ck)
{
m.flags.checked = ck;
arg_listbox arg{ item_proxy{ess_, pos}};
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
emit_checked(pos);
}
++pos.item;
}
@@ -1480,10 +1530,15 @@ namespace nana
void select_display_range(index_pair fr_abs, index_pair to_dpl, bool sel)
{
const auto already_selected = this->pick_items(true);
index_pair fr_dpl (fr_abs.cat, this->display_order(fr_abs.cat, fr_abs.item));
if (fr_dpl > to_dpl)
std::swap(fr_dpl, to_dpl);
const auto begin = fr_dpl;
const auto last = to_dpl;
for (; fr_dpl != to_dpl; forward(fr_dpl, 1, fr_dpl))
{
if (fr_dpl.is_item())
@@ -1492,6 +1547,14 @@ namespace nana
if (to_dpl.is_item())
item_proxy(ess_, index_pair(to_dpl.cat, absolute( to_dpl ) )).select(sel);
//Unselects the already selected which is out of range [begin, last]
for (auto index : already_selected)
{
index_pair disp_order{ index.cat, this->display_order(index.cat, index.item) };
if (begin > disp_order || disp_order > last)
item_proxy(ess_, index_pair(index.cat, absolute(disp_order))).select(false);
}
}
bool select_for_all(bool sel)
@@ -1508,8 +1571,7 @@ namespace nana
changed = true;
m.flags.selected = sel;
arg_listbox arg{ item_proxy(ess_, i) };
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
this->emit_selected(i);
if (m.flags.selected)
last_selected_abs = i;
@@ -1599,18 +1661,17 @@ namespace nana
return (for_selection ? m.flags.selected : m.flags.checked);
};
auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos)
auto do_cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
{
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
if (for_selection)
{
m.flags.selected = false;
widget_->events().selected.emit(arg, widget_->handle());
this->emit_selected(item_pos);
}
else
{
m.flags.checked = false;
widget_->events().checked.emit(arg, widget_->handle());
this->emit_checked(item_pos);
}
};
@@ -1622,7 +1683,7 @@ namespace nana
for (auto & m : i->items)
{
if ((item_pos != except.item) && pred(m))
do_cancel(m, except.cat, item_pos);
do_cancel(m, index_pair{ except.cat, item_pos });
++item_pos;
}
@@ -1638,7 +1699,7 @@ namespace nana
for (auto & m : cat.items)
{
if (pred(m))
do_cancel(m, cat_pos, item_pos);
do_cancel(m, index_pair{ cat_pos, item_pos });
++item_pos;
}
}
@@ -1648,7 +1709,7 @@ namespace nana
for (auto & m : cat.items)
{
if ((item_pos != except.item) && pred(m))
do_cancel(m, cat_pos, item_pos);
do_cancel(m, index_pair{ cat_pos, item_pos });
++item_pos;
}
}
@@ -1682,18 +1743,17 @@ namespace nana
return (for_selection ? m.flags.selected : m.flags.checked);
};
auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos)
auto cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
{
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
if (for_selection)
{
m.flags.selected = false;
widget_->events().selected.emit(arg, widget_->handle());
this->emit_selected(item_pos);
}
else
{
m.flags.checked = false;
widget_->events().checked.emit(arg, widget_->handle());
this->emit_checked(item_pos);
}
};
@@ -1709,7 +1769,7 @@ namespace nana
for (auto end = cat.items.end(); i != end; ++i)
{
if (pred(*i))
cancel(*i, cat_pos, i - cat.items.begin());
cancel(*i, index_pair{ cat_pos, static_cast<size_type>(i - cat.items.begin()) });
}
}
++cat_pos;
@@ -1732,7 +1792,7 @@ namespace nana
for (++i; i != end; ++i)
{
if (pred(*i))
cancel(*i, cat_pos, i - cat.items.begin());
cancel(*i, index_pair{ cat_pos, static_cast<std::size_t>(i - cat.items.begin()) });
}
}
}
@@ -1744,7 +1804,7 @@ namespace nana
for (auto & m : cat.items)
{
if (pred(m))
cancel(m, cat_pos, item_pos);
cancel(m, index_pair{ cat_pos, item_pos });
++item_pos;
}
@@ -1791,10 +1851,7 @@ namespace nana
if(m.flags.checked != ck)
{
m.flags.checked = ck;
arg_listbox arg{ item_proxy(ess_, index_pair(cat, index)) };
wd_ptr()->events().checked.emit(arg, widget_->handle());
this->emit_checked(index_pair{cat, index});
changed = true;
}
++index;
@@ -2050,7 +2107,7 @@ namespace nana
return i;
}
public:
index_pair last_selected_abs, last_selected_dpl;
index_pair last_selected_abs;
private:
essence * ess_{nullptr};
nana::listbox * widget_{nullptr};
@@ -2065,6 +2122,8 @@ namespace nana
bool single_selection_category_limited_{ false };
bool single_check_{ false };
bool single_check_category_limited_{ false };
std::vector<inline_pane*> active_panes_;
};//end class es_lister
@@ -2108,17 +2167,6 @@ namespace nana
}scroll;
struct inline_pane
{
::nana::panel<false> pane_bottom; //pane for pane_widget
::nana::panel<false> pane_widget; //pane for placing user-define widget
std::unique_ptr<inline_notifier_interface> inline_ptr;
inline_indicator * indicator;
index_pair item_pos; //The item index of the inline widget
std::size_t column_pos;
::std::string text; //text in UTF-8 encoded
};
std::map<pat::detail::abstract_factory_base*, std::deque<std::unique_ptr<inline_pane>>> inline_table, inline_buffered_table;
essence()
@@ -2963,8 +3011,8 @@ namespace nana
: ess_{ ess }, column_pos_{column_pos}
{
}
void attach(index_type pos, essence::inline_pane* pane)
void attach(index_type pos, inline_pane* pane)
{
for (auto & pn : panes_)
{
@@ -2988,6 +3036,11 @@ namespace nana
return *ess_->lister.wd_ptr();
}
std::size_t column() const override
{
return column_pos_;
}
void modify(index_type pos, const value_type& value) const override
{
ess_->lister.throw_if_immutable_model(pos);
@@ -3000,15 +3053,6 @@ namespace nana
if (cells[column_pos_].text != value)
{
for (auto & pn : panes_)
{
if (pn.first == pos)
{
pn.second->text = value;
break;
}
}
cells[column_pos_].text = value;
if (model_cells.size())
@@ -3040,7 +3084,7 @@ namespace nana
private:
essence * const ess_;
const std::size_t column_pos_;
std::vector<std::pair<index_type, essence::inline_pane*>> panes_;
std::vector<std::pair<index_type, inline_pane*>> panes_;
};
void es_lister::scroll(const index_pair& pos, bool to_bottom)
@@ -3116,7 +3160,7 @@ namespace nana
void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected)
{
auto next_selected_dpl = relative_pair ( last_selected_abs); // last_selected_dpl; // ??
auto next_selected_dpl = relative_pair ( last_selected_abs);
if (next_selected_dpl.empty()) // has no cat ? (cat == npos) => beging from first cat
{
bool good = false;
@@ -3237,7 +3281,7 @@ namespace nana
if (it.selected() != sel)
it.select(sel);
}
last_selected_abs = last_selected_dpl = index_pair{cat, npos};
last_selected_abs = index_pair{cat, npos};
}
class drawer_header_impl
@@ -3520,15 +3564,19 @@ namespace nana
public:
using item_state = essence::item_state;
using parts = essence::parts;
using status_type = inline_notifier_interface::status_type;
drawer_lister_impl(essence * es)
:essence_(es)
{}
void draw(const nana::rectangle& rect) const
void draw(const nana::rectangle& rect)
{
internal_scope_guard lock;
//clear active panes
essence_->lister.append_active_panes(nullptr);
//The count of items to be drawn
auto item_count = essence_->number_of_lister_items(true);
if (0 == item_count)
@@ -3711,7 +3759,7 @@ namespace nana
nana::color bgcolor,
nana::color fgcolor,
item_state state
) const
)
{
auto & item = cat.items[item_pos.item];
@@ -3825,35 +3873,31 @@ namespace nana
else
visible_state = false;
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
inline_wdg->pane_widget.size(sz);
inline_wdg->inline_ptr->resize(sz);
draw_column = inline_wdg->inline_ptr->whether_to_draw();
inline_wdg->item_pos = item_pos;
inline_wdg->column_pos = column_pos;
inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos);
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
inline_wdg->pane_widget.size(sz);
inline_wdg->inline_ptr->resize(sz);
inline_wdg->inline_ptr->notify_status(status_type::selected, item.flags.selected);
inline_wdg->inline_ptr->notify_status(status_type::checked, item.flags.checked);
inline_wdg->indicator->attach(item_pos, inline_wdg);
//To reduce the memory usage, the cells may not be allocated
if (cells.size() > column_pos)
{
auto & text = cells[column_pos].text;
if (text != inline_wdg->text)
{
inline_wdg->text = text;
inline_wdg->inline_ptr->set(text);
}
}
inline_wdg->inline_ptr->set(cells[column_pos].text);
else
{
inline_wdg->text.clear();
inline_wdg->inline_ptr->set({});
}
API::show_window(inline_wdg->pane_bottom, visible_state);
essence_->lister.append_active_panes(inline_wdg);
}
}
@@ -3903,18 +3947,20 @@ namespace nana
_m_draw_border(content_r.x, y, show_w);
}
essence::inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const
inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const
{
if (column_pos < cat.factories.size())
{
auto & factory = cat.factories[column_pos];
if (factory)
{
return essence_->open_inline(factory.get(), cat.indicators[column_pos].get());
}
}
return nullptr;
}
essence::inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const
inline_pane* _m_find_inline_pane(const index_pair& pos, std::size_t column_pos) const
{
auto & cat = *essence_->lister.get(pos.cat);
@@ -4151,7 +4197,18 @@ namespace nana
if (!lister.single_selection())
{
if (arg.shift)
lister.select_display_range(lister.last_selected_abs , item_pos, sel);
{
//Set the first item as the begin of selected item if there
//is not a last selected item.(#154 reported by RenaudAlpes)
if (lister.last_selected_abs.empty() || lister.last_selected_abs.is_category())
lister.last_selected_abs.set_both(0);
auto before = lister.last_selected_abs;
lister.select_display_range(lister.last_selected_abs, item_pos, sel);
lister.last_selected_abs = before;
}
else if (arg.ctrl)
sel = !item_proxy(essence_, abs_item_pos).selected();
else
@@ -4167,19 +4224,20 @@ namespace nana
if(item_ptr)
{
item_ptr->flags.selected = sel;
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } };
lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle());
if (item_ptr->flags.selected)
if (item_ptr->flags.selected != sel)
{
lister.cancel_others_if_single_enabled(true, abs_item_pos);
essence_->lister.last_selected_abs = abs_item_pos;
item_ptr->flags.selected = sel;
lister.emit_selected(abs_item_pos);
if (item_ptr->flags.selected)
{
lister.cancel_others_if_single_enabled(true, abs_item_pos);
essence_->lister.last_selected_abs = abs_item_pos;
}
else if (essence_->lister.last_selected_abs == abs_item_pos)
essence_->lister.last_selected_abs.set_both(npos);
}
else if (essence_->lister.last_selected_abs == abs_item_pos)
essence_->lister.last_selected_abs.set_both(npos);
}
else if(!lister.single_selection())
lister.categ_selected(item_pos.cat, true);
@@ -4190,8 +4248,7 @@ namespace nana
{
item_ptr->flags.checked = ! item_ptr->flags.checked;
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } };
lister.wd_ptr()->events().checked.emit(arg, lister.wd_ptr()->handle());
lister.emit_checked(abs_item_pos);
if (item_ptr->flags.checked)
lister.cancel_others_if_single_enabled(false, abs_item_pos);
@@ -4456,12 +4513,13 @@ namespace nana
item_proxy & item_proxy::check(bool ck)
{
internal_scope_guard lock;
auto & m = cat_->items.at(pos_.item);
if(m.flags.checked != ck)
{
m.flags.checked = ck;
arg_listbox arg{*this};
ess_->lister.wd_ptr()->events().checked.emit(arg, ess_->lister.wd_ptr()->handle());
ess_->lister.emit_checked(pos_);
ess_->update();
}
return *this;
@@ -4475,13 +4533,14 @@ 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)
{
internal_scope_guard lock;
//pos_ never represents a category if this item_proxy is available.
auto & m = cat_->items.at(pos_.item); // a ref to the real item
if(m.flags.selected == s) return *this; // ignore if no change
m.flags.selected = s; // actually change selection
arg_listbox arg{*this};
ess_->lister.wd_ptr()->events().selected.emit(arg, ess_->lister.wd_ptr()->handle());
ess_->lister.emit_selected(this->pos_);
if (m.flags.selected)
{
@@ -4750,10 +4809,11 @@ namespace nana
for (item_proxy &it : *this )
it.select(sel);
ess_->lister.last_selected_abs = ess_->lister.last_selected_dpl = index_pair {this->pos_, npos};
ess_->lister.last_selected_abs = index_pair {this->pos_, npos};
return *this;
}
bool cat_proxy::selected() const
{
for (item_proxy &it : *this )

View File

@@ -441,6 +441,9 @@ namespace nana{ namespace widgets
text_ptr = &mask_str;
}
if (pos.x > text_ptr->size())
pos.x = text_ptr->size();
pos.x = editor_._m_pixels_by_char(*text_ptr, pos.x) + editor_.text_area_.area.x;
int pos_y = static_cast<int>((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base());
@@ -1990,20 +1993,22 @@ namespace nana{ namespace widgets
//move_caret
//Set caret position through text coordinate
void text_editor::move_caret(const upoint& crtpos)
{
if (!API::is_focus_ready(window_))
return;
bool text_editor::move_caret(const upoint& crtpos, bool reset_caret)
{
const unsigned line_pixels = line_height();
auto pos = impl_->capacities.behavior->caret_to_screen(crtpos);
const int line_bottom = pos.y + static_cast<int>(line_pixels);
if (reset_caret)
points_.caret = this->impl_->capacities.behavior->screen_to_caret(pos);
if (!API::is_focus_ready(window_))
return false;
auto caret = API::open_caret(window_, true);
auto text_area = _m_text_area();
bool visible = false;
auto text_area = _m_text_area();
if (text_area.is_hit(pos) && (line_bottom > text_area.y))
{
visible = true;
@@ -2019,6 +2024,16 @@ namespace nana{ namespace widgets
caret->visible(visible);
if(visible)
caret->position(pos);
//Adjust the caret into screen when the caret position is modified by this function
if (reset_caret && (!hit_text_area(pos)))
{
impl_->capacities.behavior->adjust_caret_into_screen();
render(true);
caret->visible(true);
return true;
}
return false;
}
void text_editor::move_caret_end()
@@ -2507,6 +2522,11 @@ namespace nana{ namespace widgets
_m_scrollbar();
}
void text_editor::set_undo_queue_length(std::size_t len)
{
impl_->undo.max_steps(len);
}
void text_editor::move_ns(bool to_north)
{
const bool redraw_required = _m_cancel_select(0);

View File

@@ -345,8 +345,8 @@ namespace drawerbase {
{
auto editor = get_drawer_trigger().editor();
internal_scope_guard lock;
if (editor)
editor->move_caret(pos);
if (editor && editor->move_caret(pos, true))
API::refresh_window(handle());
return *this;
}
@@ -628,6 +628,14 @@ namespace drawerbase {
editor->select_behavior(move_to_end);
}
void textbox::set_undo_queue_length(std::size_t len)
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if (editor)
editor->set_undo_queue_length(len);
}
//Override _m_caption for caption()
auto textbox::_m_caption() const throw() -> native_string_type
{

View File

@@ -382,12 +382,6 @@ namespace nana
}
//class widget_base
widget_base::~widget_base()
{
if (handle_)
API::close_window(handle_);
}
window widget_base::handle() const
{
return handle_;