From c348ec40095c55f947f5b72720b96bc0222359e6 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 10 Sep 2017 13:33:38 +0800 Subject: [PATCH 01/11] fix bug that widgets are mistakenly drawn on nested_form(#252) --- source/gui/detail/window_layout.cpp | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 6c3b7578..27357217 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -149,33 +149,34 @@ namespace nana // reads the overlaps that are overlapped a rectangular block bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector& blocks) { + auto const is_wd_root = (category::flags::root == wd->other.category); wd_rectangle block; while (wd->parent) { - auto & siblings = wd->parent->children; - //It should be checked that whether the window is still a chlid of its parent. - if (siblings.size()) + auto i = std::find(wd->parent->children.cbegin(), wd->parent->children.cend(), wd); + if (i != wd->parent->children.cend()) { - auto i = &(siblings[0]); - auto *end = i + siblings.size(); - i = std::find(i, end, wd); - if (i != end) + for (++i; i != wd->parent->children.cend(); ++i) { - //find the widget that next to wd. - for (++i; i < end; ++i) + core_window_t* cover = *i; + + if (!cover->visible) + continue; + + if (is_wd_root ? + (category::flags::root == cover->other.category) + : + ((category::flags::root != cover->other.category) && (nullptr == cover->effect.bground))) { - core_window_t* cover = *i; - if ((category::flags::root != cover->other.category) && cover->visible && (nullptr == cover->effect.bground)) + if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) { - if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) - { - block.window = cover; - blocks.push_back(block); - } + block.window = cover; + blocks.push_back(block); } } } } + wd = wd->parent; } return (!blocks.empty()); From 8cb29a1617e2be8d34530e6fb09f1bdff644623c Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Mon, 11 Sep 2017 14:42:20 +0800 Subject: [PATCH 02/11] fix issue that filebox incorrectly loads folder tree on Linux --- source/gui/filebox.cpp | 14 +++++++------- source/gui/widgets/treebox.cpp | 17 ++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index c3fa7fb0..89382828 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -435,20 +435,20 @@ namespace nana nodes_.filesystem = tree_.insert("FS.ROOT", "Filesystem"); nodes_.filesystem.value(kind::filesystem); - std::vector paths; - paths.emplace_back(fs_ext::path_user().native()); - paths.emplace_back("/"); + std::vector> paths; + paths.emplace_back(fs_ext::path_user().native(), nodes_.home); + paths.emplace_back("/", nodes_.filesystem); fs::directory_iterator end; for (auto & p : paths) { - for (fs::directory_iterator i(p); i != end; ++i) + for (fs::directory_iterator i{p.first}; i != end; ++i) { auto name = i->path().filename().native(); if (!is_directory(i->status()) || (name.size() && name[0] == '.')) continue; - item_proxy node = tree_.insert(nodes_.filesystem, name, name); + item_proxy node = tree_.insert(p.second, name, name); if (false == node.empty()) { node.value(kind::filesystem); @@ -831,8 +831,8 @@ namespace nana { for(fs::directory_iterator u(i->path()); u != end; ++u) { - auto uname = i->path().filename().native(); - if ((!is_directory(*i)) || (uname.size() && uname[0] == '.')) + auto uname = u->path().filename().native(); + if ((!is_directory(*u)) || (uname.size() && uname[0] == '.')) continue; child.append(uname, uname, kind::filesystem); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 906bd969..88468861 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1825,7 +1825,6 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); - bool has_redraw = false; auto & node_state = impl_->node_state; node_state.pressed_node = nl.node(); @@ -1834,21 +1833,17 @@ namespace nana { if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded)) impl_->make_adjust(node_state.pressed_node, 0); - - has_redraw = true; //btw, don't select the node } - - if ((!has_redraw) && (node_state.selected != node_state.pressed_node)) + else if (node_state.selected != node_state.pressed_node) { impl_->set_selected(node_state.pressed_node); - has_redraw = true; } + else + return; - if(has_redraw) - { - impl_->draw(true); - API::dev::lazy_refresh(); - } + + impl_->draw(true); + API::dev::lazy_refresh(); } void trigger::mouse_up(graph_reference, const arg_mouse& arg) From b0a58ed62f2cfa438131c9f6a3eb6362942955e0 Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Mon, 11 Sep 2017 15:54:42 +0800 Subject: [PATCH 03/11] fix issue that filebox throws exception when permission denied(#251) --- source/gui/filebox.cpp | 75 +++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index 89382828..96f1e1c6 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -569,28 +569,63 @@ namespace nana if(cat_path.size() && cat_path[cat_path.size() - 1] != '/') cat_path += '/'; + auto beg = head.size(); while(true) { auto pos = path.find('/', beg); auto folder = path.substr(beg, pos != path.npos ? pos - beg: path.npos); - if(folder.size() == 0) break; + + if(folder.empty()) + break; + (cat_path += folder) += '/'; (head += folder) += '/'; path_.caption(cat_path); - for(fs::directory_iterator i(head); i != end; ++i) + try { - if (is_directory(*i)) - path_.childset(i->path().filename().native(), 0); + for(fs::directory_iterator i(head); i != end; ++i) + { + if (is_directory(*i)) + path_.childset(i->path().filename().native(), 0); + } + } + catch(fs::filesystem_error&) + { + //The directory iterator may throw filesystem_error when + //the user doesn't have permission to access the directory. + + //It just loads the sub-directories + //to the category path. } if(pos == path.npos) break; beg = pos + 1; } - _m_load_path(path); - _m_list_fs(); + + try + { + _m_load_path(path); + _m_list_fs(); + } + catch(fs::filesystem_error&) + { + file_container_.clear(); + + drawing dw{ls_file_}; + dw.clear(); + dw.draw([](paint::graphics& graph){ + std::string text = "Permission denied to access the directory"; + auto txt_sz = graph.text_extent_size(text); + auto sz = graph.size(); + + graph.string({static_cast(sz.width - txt_sz.width) / 2, static_cast(sz.height - txt_sz.height) / 2}, text, colors::dark_gray); + }); + + ls_file_.clear(); + } } bool _m_filter_allowed(const std::string& name, bool is_dir, const std::string& filter, const std::vector* extension) const @@ -611,6 +646,8 @@ namespace nana void _m_list_fs() { + drawing{ls_file_}.clear(); + auto filter = filter_.caption(); ls_file_.auto_draw(false); @@ -829,14 +866,28 @@ namespace nana auto child = node.append(name, name, kind::filesystem); if(!child.empty()) { - for(fs::directory_iterator u(i->path()); u != end; ++u) + //The try-catch can be eleminated by using + //directory_iterator( const std::filesystem::path& p, std::error_code& ec ) noexcept; + //in C++17 + try { - auto uname = u->path().filename().native(); - if ((!is_directory(*u)) || (uname.size() && uname[0] == '.')) - continue; + for(fs::directory_iterator u(i->path()); u != end; ++u) + { + auto uname = u->path().filename().native(); + if ((!is_directory(*u)) || (uname.size() && uname[0] == '.')) + continue; - child.append(uname, uname, kind::filesystem); - break; + child.append(uname, uname, kind::filesystem); + break; + } + } + catch(fs::filesystem_error&) + { + //The directory iterator may throw filesystem_error when + //the user doesn't have permission to access the directory. + + //Catch the error without any process, because the loop is just + //to peak whether the directory(i->path) has a sub-directory. } } } From 803acb13f0a85ea9b5048c429ae21d02d64b2f5a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 12 Sep 2017 08:15:22 +0800 Subject: [PATCH 04/11] fix move-ctor and move-assignement operator of graphics(#253) --- source/paint/graphics.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index b7dd3426..c617b3ee 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -240,12 +240,16 @@ namespace paint graphics::graphics(graphics&& other) : impl_(std::move(other.impl_)) { + other.impl_.reset(new implementation); } graphics& graphics::operator=(graphics&& other) { if (this != &other) + { impl_ = std::move(other.impl_); + other.impl_.reset(new implementation); + } return *this; } From c45f621eeab9e7f739ef0afddb38f05dd45e2f1e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 13 Sep 2017 04:58:05 +0800 Subject: [PATCH 05/11] fix crash where text_editor enables the linewrap(#254) --- source/gui/widgets/skeletons/text_editor.cpp | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index f39638b2..5688b2be 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -556,6 +556,7 @@ namespace nana{ namespace widgets virtual void merge_lines(std::size_t first, std::size_t second) = 0; //Calculates how many lines the specified line of text takes with a specified pixels of width. virtual void add_lines(std::size_t pos, std::size_t lines) = 0; + virtual void prepare() = 0; virtual void pre_calc_line(std::size_t line, unsigned pixels) = 0; virtual void pre_calc_lines(unsigned pixels) = 0; virtual std::size_t take_lines() const = 0; @@ -668,6 +669,12 @@ namespace nana{ namespace widgets } } + void prepare() override + { + auto const line_count = editor_.textbase().lines(); + this->sections_.resize(line_count); + } + void pre_calc_line(std::size_t pos, unsigned) override { auto const & text = editor_.textbase().getline(pos); @@ -781,6 +788,12 @@ namespace nana{ namespace widgets } } + void prepare() override + { + auto const lines = editor_.textbase().lines(); + linemtr_.resize(lines); + } + void pre_calc_line(std::size_t line, unsigned pixels) override { const string_type& lnstr = editor_.textbase().getline(line); @@ -1234,7 +1247,7 @@ namespace nana{ namespace widgets void text_editor::typeface_changed() { - impl_->capacities.behavior->pre_calc_lines(width_pixels()); + _m_reset_content_size(true); } void text_editor::indent(bool enb, std::function generator) @@ -2886,10 +2899,14 @@ namespace nana{ namespace widgets auto text_lines = textbase().lines(); if (text_lines <= max_lines) { + impl_->capacities.behavior->prepare(); + + auto const width_px = _m_width_px(true); + std::size_t lines = 0; for (std::size_t i = 0; i < text_lines; ++i) { - impl_->capacities.behavior->pre_calc_line(i, csize.width); + impl_->capacities.behavior->pre_calc_line(i, width_px); lines += impl_->capacities.behavior->take_lines(i); if (lines > max_lines) From 6e9296166f395bbd0c4b49d055116551a9342a14 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 14 Sep 2017 02:21:03 +0800 Subject: [PATCH 06/11] fix bug that platform_spec_posix.cpp is missing in code::blocks project --- build/codeblocks/nana.cbp | 1 + 1 file changed, 1 insertion(+) diff --git a/build/codeblocks/nana.cbp b/build/codeblocks/nana.cbp index c598a95d..18c78755 100644 --- a/build/codeblocks/nana.cbp +++ b/build/codeblocks/nana.cbp @@ -50,6 +50,7 @@ + From dbc9bc55ff5bd055f2f01c80d119e35a7a981f41 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 18 Sep 2017 23:36:40 +0800 Subject: [PATCH 07/11] fix bug that fast clicking a spinbox doesn't change the value(#257) --- include/nana/gui/widgets/spinbox.hpp | 1 + source/gui/widgets/spinbox.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index 2ecabc78..15cbc694 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -61,6 +61,7 @@ namespace nana void focus(graph_reference, const arg_focus&) override; void mouse_wheel(graph_reference, const arg_wheel&) override; + void dbl_click(graph_reference, const arg_mouse&) override; void mouse_down(graph_reference, const arg_mouse&) override; void mouse_move(graph_reference, const arg_mouse&) override; void mouse_up(graph_reference, const arg_mouse& arg) override; diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 2fad022f..89423eab 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -560,6 +560,12 @@ namespace nana impl_->editor()->reset_caret(); API::dev::lazy_refresh(); } + + void drawer::dbl_click(graph_reference, const arg_mouse& arg) + { + if (impl_->mouse_button(arg, true)) + API::dev::lazy_refresh(); + } void drawer::mouse_down(graph_reference, const arg_mouse& arg) { From c1654f75eca2ea61fa18f86fc8c49d58ee5eb539 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 18 Sep 2017 23:46:02 +0800 Subject: [PATCH 08/11] fix issue that typing text for spinbox doesn't draw spin buttons border --- source/gui/widgets/spinbox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 89423eab..41b592f3 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -605,7 +605,10 @@ namespace nana { impl_->editor()->respond_char(arg); if (impl_->editor()->try_refresh()) + { + impl_->draw_spins(); API::dev::lazy_refresh(); + } } void drawer::resized(graph_reference, const arg_resized&) From bb47cdc6c9711c366f2fc5bd7e369ad2eab9f2fc Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Fri, 22 Sep 2017 15:47:12 +0800 Subject: [PATCH 09/11] fix bug that DEL key is incorrect in key_press/key_release(#259) --- include/nana/gui/basis.hpp | 6 ++++-- source/gui/detail/bedrock_posix.cpp | 4 ++-- source/gui/detail/bedrock_windows.cpp | 17 +++++++++++++++-- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index a13b3bac..69b97c1f 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -91,6 +91,8 @@ namespace nana substitute = 0x1A, //Ctrl+Z escape = 0x1B, space = 0x20, //Space + del = 0x7F, //Delete + os_del = del, //Deprecated //The following names are intuitive name of ASCII control codes select_all = start_of_headline, @@ -106,8 +108,8 @@ namespace nana os_ctrl = 0x11, os_pageup = 0x21, os_pagedown, os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, - os_insert = 0x2D, os_del , - os_end = 0x23 , os_home //Pos 1 + os_insert = 0x2D, + os_end = 0x23, os_home //Pos 1 }; }; diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 9b0e24e0..4e7c8a07 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -438,8 +438,8 @@ namespace detail keysym = keyboard::os_arrow_left + (keysym - XK_Left); break; case XK_Insert: keysym = keyboard::os_insert; break; - case XK_Delete: - keysym = keyboard::os_del; break; + case XK_Delete: case XK_KP_Delete: + keysym = keyboard::del; break; case XK_Shift_L: case XK_Shift_R: //shift keysym = keyboard::os_shift; break; case XK_Control_L: case XK_Control_R: //ctrl diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index ebf32705..67f40ffe 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -775,6 +775,19 @@ namespace detail if (thrd) thrd->event_window = prev_event_wd; } + //Translate OS Virtual-Key into ASCII code + wchar_t translate_virtual_key(WPARAM vkey) + { + switch (vkey) + { + case VK_DELETE: + return 127; + case VK_DECIMAL: + return 46; + } + return static_cast(vkey); + } + LRESULT CALLBACK Bedrock_WIN32_WindowProc(HWND root_window, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT window_proc_value = 0; @@ -1436,7 +1449,7 @@ namespace detail arg.evt_code = event_code::key_press; arg.window_handle = reinterpret_cast(msgwnd); arg.ignore = false; - arg.key = static_cast(wParam); + arg.key = translate_virtual_key(wParam); brock.get_key_state(arg); brock.emit(event_code::key_press, msgwnd, arg, true, &context); @@ -1522,7 +1535,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; arg.window_handle = reinterpret_cast(msgwnd); - arg.key = static_cast(wParam); + arg.key = translate_virtual_key(wParam); brock.get_key_state(arg); arg.ignore = false; brock.emit(event_code::key_release, msgwnd, arg, true, &context); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 5688b2be..72cec7ee 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1233,7 +1233,7 @@ namespace nana{ namespace widgets case keyboard::os_pagedown: _m_handle_move_key(arg); break; - case keyboard::os_del: + case keyboard::del: // send delete to set_accept function if (this->attr().editable && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key))) del(); From eec7344c6d11616b2198d8889e1e9ad29d7cb93a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 23 Sep 2017 07:25:16 +0800 Subject: [PATCH 10/11] fix issue that typing text for spinbox doesn't draw spin buttons border --- source/gui/widgets/skeletons/text_editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 72cec7ee..fefaf1ed 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1689,7 +1689,7 @@ namespace nana{ namespace widgets impl_->try_refresh = sync_graph::refresh; //_m_put calcs the lines - _m_reset_content_size(false); + _m_reset_content_size(true); impl_->cview->sync(false); } } From 13761be5e9d83a8a49158efc1bb151e8d810b570 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 23 Sep 2017 07:33:31 +0800 Subject: [PATCH 11/11] fix crash where a menubar popups a menu and exits by shortcut(#261) --- source/gui/widgets/menubar.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index a83c3d86..5071c094 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -403,8 +403,15 @@ namespace nana ess_->state.nullify_mouse = true; auto & menu_ptr = ess_->state.menu; + + //menu_wd will be assigned with the handle of a menu window, + //It is used for checking whether the menu is closed. A menu handler + //may close the form, checking with the data member of this trigger + //is invalid, because the form is closed, the object of menubar may not exist. + window menu_wd = nullptr; if(ess_->state.menu) { + menu_wd = menu_ptr->handle(); switch(arg.key) { case keyboard::os_arrow_down: @@ -466,8 +473,11 @@ namespace nana case keyboard::os_arrow_up: case keyboard::os_arrow_down: case keyboard::enter: - if(ess_->open_menu(true)) + if (ess_->open_menu(true)) + { + menu_wd = menu_ptr->handle(); menu_ptr->goto_next(true); + } break; case keyboard::escape: if(essence::behavior::focus == ess_->state.behave) @@ -481,15 +491,21 @@ namespace nana if(index != npos) { ess_->state.active = index; - if(ess_->open_menu(true)) + if (ess_->open_menu(true)) + { + menu_wd = menu_ptr->handle(); menu_ptr->goto_next(true); + } } break; } } - refresh(graph); - API::dev::lazy_refresh(); + if (API::is_window(menu_wd)) + { + refresh(graph); + API::dev::lazy_refresh(); + } } void trigger::key_release(graph_reference graph, const arg_keyboard& arg)