From e2910ce5d911389b456c57d32582c74fced73488 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 13 May 2017 08:07:57 +0800 Subject: [PATCH 01/28] fix issue that Ctrl+A selects all items in single-selection listbox(#205) --- source/gui/widgets/listbox.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1a3325ec..1de525f9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4320,9 +4320,12 @@ namespace nana return; } case keyboard::select_all : - essence_->lister.select_for_all(true); - refresh(graph); - API::dev::lazy_refresh(); + if (!essence_->lister.single_status(true)) + { + essence_->lister.select_for_all(true); + refresh(graph); + API::dev::lazy_refresh(); + } break; default: return; From ced53b3927eaa73465ae4743d50ebfd66a05ed23 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 13 May 2017 08:14:43 +0800 Subject: [PATCH 02/28] fix bug that listbox wouldn't update when clicks on blank area --- source/gui/widgets/listbox.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1de525f9..b2939abe 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -4138,6 +4138,13 @@ namespace nana essence_->start_mouse_selection(arg.pos); lister.select_for_all(false); + update = true; + if (good_list_r) + { + drawer_lister_->draw(list_r); + if (good_head_r) + drawer_header_->draw(graph, head_r); + } } if(update) From d85383e0f8bde85d5c1f0e66383013cd1db4a294 Mon Sep 17 00:00:00 2001 From: codicodi Date: Sun, 14 May 2017 15:16:14 +0200 Subject: [PATCH 03/28] CMake: fix NANA_LINKS for MSVC --- CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f0dc030..20189f26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ endif(WIN32) if(APPLE) add_definitions(-DAPPLE) include_directories(/opt/X11/include/) - set(NANA_LINKS "${NANA_LINKS} -L/opt/X11/lib/ -liconv") + list(APPEND NANA_LINKS -L/opt/X11/lib/ -liconv) set(ENABLE_AUDIO OFF) elseif(UNIX) add_definitions(-Dlinux) @@ -108,11 +108,11 @@ elseif(UNIX) endif(APPLE) if(UNIX) - set(NANA_LINKS "${NANA_LINKS} -lX11") + list(APPEND NANA_LINKS -lX11) find_package(Freetype) if (FREETYPE_FOUND) include_directories( ${FREETYPE_INCLUDE_DIRS}) - set(NANA_LINKS "${NANA_LINKS} -lXft") + list(APPEND NANA_LINKS -lXft) endif(FREETYPE_FOUND) endif(UNIX) @@ -140,13 +140,13 @@ endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # enable static linkage # GNU || CLang not MinGW if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW # set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread") - set(NANA_LINKS "${NANA_LINKS} -static-libgcc -static-libstdc++ -pthread") + list(APPEND NANA_LINKS -static-libgcc -static-libstdc++ -pthread) # message("Setting NANA_LINKS to -static-libgcc -static-libstdc++ -pthread or ${NANA_LINKS}") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3) # IS_GNUCXX < 5.3 else(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3) # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++fs") # IS_GNUCXX 5.3 or more - set(NANA_LINKS "${NANA_LINKS} -lstdc++fs") + list(APPEND NANA_LINKS -lstdc++fs) endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3) endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW @@ -154,7 +154,7 @@ endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang # set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++") - set(NANA_LINKS "${NANA_LINKS} -stdlib=libstdc++") + list(APPEND NANA_LINKS -stdlib=libstdc++) endif () @@ -163,11 +163,11 @@ endif () # Find PNG if(NANA_CMAKE_ENABLE_PNG) add_definitions(-DNANA_ENABLE_PNG) - set(NANA_LINKS "${NANA_LINKS} -lpng") if(NANA_CMAKE_LIBPNG_FROM_OS) find_package(PNG) if (PNG_FOUND) include_directories( ${PNG_INCLUDE_DIRS}) + list(APPEND NANA_LINKS ${PNG_LIBRARIES}) add_definitions(-DUSE_LIBPNG_FROM_OS) endif(PNG_FOUND) endif(NANA_CMAKE_LIBPNG_FROM_OS) @@ -176,11 +176,11 @@ endif(NANA_CMAKE_ENABLE_PNG) # Find JPEG if(NANA_CMAKE_ENABLE_JPEG) add_definitions(-DNANA_ENABLE_JPEG) - set(NANA_LINKS "${NANA_LINKS} -ljpeg") if(NANA_CMAKE_LIBJPEG_FROM_OS) find_package(JPEG) if (JPEG_FOUND) - include_directories( ${JPEG_INCLUDE_DIRS}) + include_directories( ${JPEG_INCLUDE_DIR}) + list(APPEND NANA_LINKS ${JPEG_LIBRARY}) add_definitions(-DUSE_LIBJPEG_FROM_OS) endif(JPEG_FOUND) endif(NANA_CMAKE_LIBJPEG_FROM_OS) @@ -193,7 +193,7 @@ if(NANA_CMAKE_ENABLE_AUDIO) find_package(ASOUND) if (ASOUND_FOUND) include_directories( ${ASOUND_INCLUDE_DIRS}) - set(NANA_LINKS "${NANA_LINKS} -lasound") + list(APPEND NANA_LINKS -lasound) else(ASOUND_FOUND) message(FATAL_ERROR "libasound is not found") endif(ASOUND_FOUND) @@ -217,7 +217,7 @@ elseif (NANA_CMAKE_FIND_BOOST_FILESYSTEM OR NANA_CMAKE_BOOST_FILESYSTEM_FORCE) if (Boost_FOUND) add_definitions(-DNANA_BOOST_FILESYSTEM_AVAILABLE) include_directories(SYSTEM "${Boost_INCLUDE_DIR}") - set(NANA_LINKS "${NANA_LINKS} ${Boost_LIBRARIES}") ###### FIRST !!!!!!!!!!!!!!!!! add is not first + list(APPEND NANA_LINKS ${Boost_LIBRARIES}) ###### FIRST !!!!!!!!!!!!!!!!! add is not first endif (Boost_FOUND) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) # ?? From 582df4c5d4d9946d4c26df0d8859524fce16f0a3 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 19 May 2017 06:19:42 +0800 Subject: [PATCH 04/28] fix issue of listbox header margin --- include/nana/gui/widgets/listbox.hpp | 11 +- source/gui/widgets/listbox.cpp | 204 +++++++++++++++++++-------- 2 files changed, 155 insertions(+), 60 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 410e5118..f3cc09df 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1395,6 +1395,11 @@ the nana::detail::basic_window member pointer scheme size_type append_header(std::string text_utf8, unsigned width = 120); size_type append_header(std::wstring text, unsigned width = 120); + cat_proxy append(std::string category); ///< Appends a new category to the end + cat_proxy append(std::wstring category); ///< Appends a new category to the end + void append(std::initializer_list categories); ///< Appends categories to the end + void append(std::initializer_list categories); ///< Appends categories to the end + /// Access a column at specified position /** * @param pos Position of column @@ -1416,10 +1421,8 @@ the nana::detail::basic_window member pointer scheme /// Returns the number of columns size_type column_size() const; - cat_proxy append(std::string category); ///< Appends a new category to the end - cat_proxy append(std::wstring category); ///< Appends a new category to the end - void append(std::initializer_list categories); ///< Appends categories to the end - void append(std::initializer_list categories); ///< Appends categories to the end + /// Returns a rectangle in where the content is drawn. + rectangle content_area() const; cat_proxy insert(cat_proxy, ::std::string); cat_proxy insert(cat_proxy, ::std::wstring); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index b2939abe..1b33d880 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -465,6 +465,28 @@ namespace nana return npos; } + unsigned margin() const + { + return margin_; + } + + std::pair range(size_type pos) const + { + int left = static_cast(margin_); + + for (auto & m : cont_) + { + if (m.index == pos) + return{left, m.width_px}; + + if (m.visible_state) + left += static_cast(m.width_px); + } + + return{ left, 0 }; + } + + /* /// Returns the left point position and width(in variable *pixels) of column originaly at position pos. int position(size_type pos, unsigned * pixels) const { @@ -483,6 +505,7 @@ namespace nana } return left; } + */ /// return the original index of the visible col currently before(in front of) or after the col originaly at index "index" size_type next(size_type index) const noexcept @@ -553,6 +576,7 @@ namespace nana private: bool visible_{true}; bool sortable_{true}; + unsigned margin_{ 5 }; container cont_; }; @@ -2203,12 +2227,10 @@ namespace nana ::nana::size calc_content_size(bool try_update = true) { size ctt_size( - this->header.pixels() + 5, - static_cast(this->lister.the_number_of_expanded()) + this->header.pixels() + this->header.margin(), + static_cast(this->lister.the_number_of_expanded()) * this->item_height() ); - ctt_size.height *= this->item_height(); - this->content_view->content_size(ctt_size, try_update); return ctt_size; @@ -2226,7 +2248,8 @@ namespace nana if (seq.empty()) return 0; - return (header.position(seq[0], nullptr) - this->content_view->origin().x + r.x); + //return (header.position(seq[0], nullptr) - this->content_view->origin().x + r.x); //deprecated + return header.range(seq.front()).first + r.x - this->content_view->origin().x; } //Returns the absolute coordinate of the specified item in the window @@ -2258,12 +2281,19 @@ namespace nana } else if (area.x <= pos.x + origin.x && pos.x + origin.x < area.x + static_cast(header.pixels())) { + // detect if cursor is in the area of header margin + if (pos.x < area.x - origin.x + static_cast(header.margin())) + return{ parts::list_blank, npos }; + new_where.first = parts::list; auto const item_h = item_height(); //don't combine the following formula into the (pos.y - area.y - header_visible_px()) / item_h new_where.second = ((pos.y - area.y - header_visible_px() + origin.y) / item_h) - (origin.y / item_h); + if (this->lister.the_number_of_expanded() < new_where.second + 1) + return{ parts::list_blank, npos }; + if (checkable) { nana::rectangle r; @@ -3042,7 +3072,8 @@ namespace nana { if(essence_->ptr_state == item_state::highlighted) { - x -= r.x - essence_->content_view->origin().x; + x -= r.x - essence_->content_view->origin().x + static_cast(essence_->header.margin()); + for(auto & col : essence_->header.cont()) // in current order { @@ -3135,21 +3166,26 @@ namespace nana 0, r.height - 1 }; + //The first item includes the margin + unsigned margin = essence_->header.margin(); + for (auto & col : essence_->header.cont()) { if (col.visible_state) { - column_r.width = col.width_px; + column_r.width = col.width_px + margin; const auto right_pos = column_r.right(); //Make sure the column is in the display area. if (right_pos > r.x) { - _m_draw_header_item(graph, column_r, text_color, col, (col.index == essence_->pointer_where.second ? state : item_state::normal)); + _m_draw_header_item(graph, margin, column_r, text_color, col, (col.index == essence_->pointer_where.second ? state : item_state::normal)); graph.line({ right_pos - 1, r.y }, { right_pos - 1, r.bottom() - 2 }, border_color); } + margin = 0; + column_r.x = right_pos; if (right_pos > r.right()) break; @@ -3189,28 +3225,35 @@ namespace nana auto i = essence_->header.column_from_point(x); - if(i == npos) - i = essence_->header.boundary(essence_->header.position(grab, nullptr) >= x); + if (i == npos) + //i = essence_->header.boundary(essence_->header.position(grab, nullptr) >= x); //deprecated + i = essence_->header.boundary(essence_->header.range(grab).first >= x); if(grab != i) { - unsigned item_pixels = 0; - auto item_x = essence_->header.position(i, &item_pixels); + //unsigned item_pixels = 0; + //auto item_x = essence_->header.position(i, &item_pixels); //deprecated + + auto item_rg = essence_->header.range(i); //Get the item pos //if mouse pos is at left of an item middle, the pos of itself otherwise the pos of the next. - place_front = (x <= (item_x + static_cast(item_pixels / 2))); - x = (place_front ? item_x : essence_->header.position(essence_->header.next(i), nullptr)); + place_front = (x <= (item_rg.first + static_cast(item_rg.second / 2))); + x = (place_front ? item_rg.first : essence_->header.range(essence_->header.next(i)).first); if (npos != i) - essence_->graph->rectangle({x - x_offset + rect.x, rect.y, 2, rect.height}, true, colors::red); + { + if (place_front && (0 == essence_->header.cast(i, false))) + x -= static_cast(essence_->header.margin()); + essence_->graph->rectangle({ x - x_offset + rect.x, rect.y, 2, rect.height }, true, colors::red); + } return i; } return npos; } - void _m_draw_header_item(graph_reference graph, const rectangle& column_r, const ::nana::color& fgcolor, const es_header::column& column, item_state state) + void _m_draw_header_item(graph_reference graph, unsigned margin, const rectangle& column_r, const ::nana::color& fgcolor, const es_header::column& column, item_state state) { ::nana::color bgcolor; @@ -3241,7 +3284,7 @@ namespace nana { graph.palette(true, fgcolor); - point text_pos{ column_r.x, (static_cast(essence_->scheme_ptr->header_height) - static_cast(essence_->text_height)) / 2 }; + point text_pos{ column_r.x + static_cast(margin), (static_cast(essence_->scheme_ptr->header_height) - static_cast(essence_->text_height)) / 2 }; if (align::left == column.alignment) text_pos.x += text_margin; @@ -3265,13 +3308,19 @@ namespace nana { const auto & col = essence_->header.at(essence_->pointer_where.second); - paint::graphics fl_graph({ col.width_px, essence_->scheme_ptr->header_height }); + auto margin = 0; + + if (&essence_->header.at(0, true) == &col) + margin = essence_->header.margin(); + + paint::graphics fl_graph({ col.width_px + margin, essence_->scheme_ptr->header_height }); fl_graph.typeface(essence_->graph->typeface()); - _m_draw_header_item(fl_graph, rectangle{ fl_graph.size()}, colors::white, col, item_state::floated); + _m_draw_header_item(fl_graph, margin, rectangle{ fl_graph.size()}, colors::white, col, item_state::floated); - auto xpos = essence_->header.position(col.index, nullptr) + pos.x - grabs_.start_pos; + //auto xpos = essence_->header.position(col.index, nullptr) + pos.x - grabs_.start_pos; //deprecated + auto xpos = essence_->header.range(col.index).first + pos.x - grabs_.start_pos; essence_->graph->blend(rectangle{ point{ xpos - essence_->content_view->origin().x + rect.x, rect.y } , fl_graph.size() }, fl_graph, {}, 0.5); } @@ -3331,23 +3380,39 @@ namespace nana auto const header_w = essence_->header.pixels(); auto const item_height_px = essence_->item_height(); - auto origin = essence_->content_view->origin(); - if (header_w < origin.x + rect.width) + auto const origin = essence_->content_view->origin(); + + auto const header_margin = essence_->header.margin(); + if (header_w + header_margin < origin.x + rect.width) { - rectangle r{ point{ rect.x + static_cast(header_w)-origin.x, rect.y }, + rectangle r{ point{ rect.x + static_cast(header_w + header_margin) - origin.x, rect.y }, size{ rect.width + origin.x - header_w, rect.height } }; if (!API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), r, *essence_->graph, r.position())) essence_->graph->rectangle(r, true); } + if (header_margin > 0) + { + rectangle r = rect; + r.width = header_margin; + + if (!API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), r, *essence_->graph, r.position())) + essence_->graph->rectangle(r, true); + } + es_lister & lister = essence_->lister; auto & ptr_where = essence_->pointer_where; - int item_top = rect.y - (origin.y % item_height_px); + //int item_top = rect.y - (origin.y % item_height_px); //deprecated auto first_disp = essence_->first_display(); + point item_coord{ + essence_->item_xpos(rect), + rect.y - static_cast(origin.y % item_height_px) + }; + // The first display is empty when the listbox is empty. if (!first_disp.empty()) { @@ -3379,7 +3444,7 @@ namespace nana ind->detach(); } - const int x = essence_->item_xpos(rect); + //const int x = essence_->item_xpos(rect); //deprecated //Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos)) if (idx.cat == 0 || !idx.is_category()) @@ -3393,16 +3458,16 @@ namespace nana std::size_t size = i_categ->items.size(); for (std::size_t offs = first_disp.item; offs < size; ++offs, ++idx.item) { - if (item_top >= rect.bottom()) + if (item_coord.y >= rect.bottom()) break; auto item_pos = lister.index_cast(index_pair{ idx.cat, offs }, true); //convert display position to absolute position - _m_draw_item(*i_categ, item_pos, x, item_top, txtoff, header_w, rect, subitems, bgcolor, fgcolor, + _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, subitems, bgcolor, fgcolor, (hoverred_pos == idx ? item_state::highlighted : item_state::normal) ); - item_top += item_height_px; + item_coord.y += static_cast(item_height_px); } ++i_categ; @@ -3411,15 +3476,15 @@ namespace nana for (; i_categ != lister.cat_container().end(); ++i_categ, ++idx.cat) { - if (item_top > rect.bottom()) + if (item_coord.y > rect.bottom()) break; idx.item = 0; - _m_draw_categ(*i_categ, rect.x - origin.x, item_top, txtoff, header_w, rect, bgcolor, + _m_draw_categ(*i_categ, rect.x - origin.x, item_coord.y, txtoff, header_w, rect, bgcolor, (hoverred_pos.is_category() && (idx.cat == hoverred_pos.cat) ? item_state::highlighted : item_state::normal) ); - item_top += item_height_px; + item_coord.y += static_cast(item_height_px); if (false == i_categ->expand) continue; @@ -3427,17 +3492,17 @@ namespace nana auto size = i_categ->items.size(); for (decltype(size) pos = 0; pos < size; ++pos) { - if (item_top > rect.bottom()) + if (item_coord.y > rect.bottom()) break; auto item_pos = lister.index_cast(index_pair{ idx.cat, pos }, true); //convert display position to absolute position - _m_draw_item(*i_categ, item_pos, x, item_top, txtoff, header_w, rect, subitems, bgcolor, fgcolor, + _m_draw_item(*i_categ, item_pos, item_coord, txtoff, header_w, rect, subitems, bgcolor, fgcolor, (idx == hoverred_pos ? item_state::highlighted : item_state::normal) ); - item_top += item_height_px; - if (item_top >= rect.bottom()) + item_coord.y += static_cast(item_height_px); + if (item_coord.y >= rect.bottom()) break; ++idx.item; @@ -3447,9 +3512,9 @@ namespace nana essence_->inline_buffered_table.clear(); } - if (item_top < rect.bottom()) + if (item_coord.y < rect.bottom()) { - rectangle bground_r{ rect.x, item_top, rect.width, static_cast(rect.bottom() - item_top) }; + rectangle bground_r{ rect.x, item_coord.y, rect.width, static_cast(rect.bottom() - item_coord.y) }; if (!API::dev::copy_transparent_background(essence_->listbox_ptr->handle(), bground_r, *essence_->graph, bground_r.position())) essence_->graph->rectangle(bground_r, true, bgcolor); } @@ -3479,7 +3544,7 @@ namespace nana { const auto item_height = essence_->item_height(); - rectangle bground_r{ x, y, width, item_height }; + rectangle bground_r{ x + static_cast(essence_->header.margin()), y, width, item_height }; auto graph = essence_->graph; item_data item; @@ -3514,7 +3579,8 @@ namespace nana //Draw selecting inner rectangle if (item.flags.selected && (categ.expand == false)) - _m_draw_item_border(r.x, y, (std::min)(r.width, width - essence_->content_view->origin().x)); + //_m_draw_item_border(r.x, y, (std::min)(r.width, width - essence_->content_view->origin().x)); //deprecated + _m_draw_item_border(y); } color _m_draw_item_bground(const rectangle& bground_r, color bgcolor, color cell_color, item_state state, const item_data& item) @@ -3563,8 +3629,7 @@ namespace nana /// Draws an item void _m_draw_item(const category_t& cat, const index_pair& item_pos, - const int x, ///< left coordinate ? - const int y, ///< top coordinate + const point& coord, const int txtoff, ///< below y to print the text unsigned width, const nana::rectangle& content_r, ///< the rectangle where the full list content have to be drawn @@ -3592,10 +3657,10 @@ namespace nana auto graph = essence_->graph; //draw the background for the whole item - rectangle bground_r{ content_r.x, y, show_w, essence_->item_height() }; + rectangle bground_r{ content_r.x + static_cast(essence_->header.margin()), coord.y, show_w, essence_->item_height() }; auto const state_bgcolor = this->_m_draw_item_bground(bground_r, bgcolor, {}, state, item); - int column_x = x; + int column_x = coord.x; for (size_type display_order{ 0 }; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed { @@ -3638,8 +3703,8 @@ namespace nana { nana::rectangle imgt(item.img_show_size); img_r = imgt; - img_r.x = content_pos + column_x + (16 - static_cast(item.img_show_size.width)) / 2; // center in 16 - geom scheme? - img_r.y = y + (static_cast(essence_->item_height()) - static_cast(item.img_show_size.height)) / 2; // center + img_r.x = content_pos + coord.x + (16 - static_cast(item.img_show_size.width)) / 2; // center in 16 - geom scheme? + img_r.y = coord.y + (static_cast(essence_->item_height()) - static_cast(item.img_show_size.height)) / 2; // center } content_pos += 18; // image width, geom scheme? } @@ -3655,18 +3720,18 @@ namespace nana //Make sure the user-define inline widgets is in the right visible rectangle. rectangle pane_r; - const auto wdg_x = column_x + content_pos; + const auto wdg_x = coord.x + content_pos; const auto wdg_w = col.width_px - static_cast(content_pos); bool visible_state = true; - if (::nana::overlap(content_r, { wdg_x, y, wdg_w, essence_->item_height() }, pane_r)) + if (::nana::overlap(content_r, { wdg_x, coord.y, wdg_w, essence_->item_height() }, pane_r)) { ::nana::point pane_pos; if (wdg_x < content_r.x) pane_pos.x = wdg_x - content_r.x; - if (y < content_r.y) - pane_pos.y = y - content_r.y; + if (coord.y < content_r.y) + pane_pos.y = coord.y - content_r.y; inline_wdg->pane_widget.move(pane_pos); inline_wdg->pane_bottom.move(pane_r); @@ -3713,7 +3778,7 @@ namespace nana { col_fgcolor = m_cell.custom_format->fgcolor; - bground_r = rectangle{ column_x, y, col.width_px, essence_->item_height() }; + bground_r = rectangle{ column_x, coord.y, col.width_px, essence_->item_height() }; col_bgcolor = this->_m_draw_item_bground(bground_r, bgcolor, m_cell.custom_format->bgcolor, state, item); } else @@ -3730,27 +3795,29 @@ namespace nana text_margin_right = essence_->scheme_ptr->text_margin; graph->palette(true, col_fgcolor); - text_aligner.draw(m_cell.text, { column_x + content_pos, y + txtoff }, col.width_px - content_pos - text_margin_right); + text_aligner.draw(m_cell.text, { column_x + content_pos, coord.y + txtoff }, col.width_px - content_pos - text_margin_right); } } if (0 == display_order) { if (essence_->checkable) - crook_renderer_.draw(*graph, col_bgcolor, col_fgcolor, essence_->checkarea(column_x, y), estate); + crook_renderer_.draw(*graph, col_bgcolor, col_fgcolor, essence_->checkarea(column_x, coord.y), estate); if (item.img) item.img.stretch(rectangle{ item.img.size() }, *graph, img_r); } - graph->line({ column_x - 1, y }, { column_x - 1, y + static_cast(essence_->item_height()) - 1 }, static_cast(0xEBF4F9)); + if (display_order > 0) + graph->line({ column_x - 1, coord.y }, { column_x - 1, coord.y + static_cast(essence_->item_height()) - 1 }, static_cast(0xEBF4F9)); } column_x += col.width_px; } //Draw selecting inner rectangle - if(item.flags.selected) - _m_draw_item_border(content_r.x, y, show_w); + if (item.flags.selected) + //_m_draw_item_border(content_r.x, coord.y, show_w); //deprecated + _m_draw_item_border(coord.y); } inline_pane * _m_get_inline_pane(const category_t& cat, std::size_t column_pos) const @@ -3789,9 +3856,10 @@ namespace nana return nullptr; } - void _m_draw_item_border(int x, int y, unsigned width) const + void _m_draw_item_border(int item_top) const { //Draw selecting inner rectangle + /* rectangle r{ x, y, width, essence_->item_height() }; essence_->graph->rectangle(r, false, static_cast(0x99defd)); @@ -3799,6 +3867,21 @@ namespace nana essence_->graph->palette(false, colors::white); paint::draw(*essence_->graph).corner(r, 1); + essence_->graph->rectangle(r.pare_off(1), false); + */ + + rectangle r{ + essence_->content_area().x - essence_->content_view->origin().x + static_cast(essence_->header.margin()), + item_top, + essence_->header.pixels(), + essence_->item_height() + }; + + essence_->graph->rectangle(r, false, static_cast(0x99defd)); + + essence_->graph->palette(false, colors::white); + paint::draw(*essence_->graph).corner(r, 1); + essence_->graph->rectangle(r.pare_off(1), false); } private: @@ -5150,6 +5233,15 @@ namespace nana ess.update(); } + rectangle listbox::content_area() const + { + auto & ess = _m_ess(); + auto carea = ess.content_area(); + carea.x += ess.header.margin(); + carea.width -= (std::min)(carea.width, ess.header.margin()); + return carea; + } + auto listbox::insert(cat_proxy cat, std::string str) -> cat_proxy { internal_scope_guard lock; From 260715dd0beae3363e43cdfa597709871e6bb070 Mon Sep 17 00:00:00 2001 From: FirstTimeInForever Date: Sun, 21 May 2017 02:11:43 +0300 Subject: [PATCH 05/28] Fix VS2017 project win32 config For some reason win32 configuration was broken. There were no include paths and other stuff were just set to their defaults. --- build/vc2017/nana.vcxproj | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/build/vc2017/nana.vcxproj b/build/vc2017/nana.vcxproj index 6ee38270..b1e450b8 100644 --- a/build/vc2017/nana.vcxproj +++ b/build/vc2017/nana.vcxproj @@ -23,7 +23,7 @@ {42D0520F-EFA5-4831-84FE-2B9085301C5D} Win32Proj nana - 10.0.14393.0 + 10.0.15063.0 @@ -82,6 +82,18 @@ ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + From a4f15f7bb08100221aa5b314e679facc59871f6d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 23 May 2017 04:22:08 +0800 Subject: [PATCH 06/28] refactor text_editor fix issues that caret works incorrectly in line-wrapped mode. --- .../gui/widgets/skeletons/text_editor.hpp | 13 +- .../nana/gui/widgets/skeletons/textbase.hpp | 109 ++-- source/gui/widgets/skeletons/content_view.cpp | 33 +- source/gui/widgets/skeletons/content_view.hpp | 1 + source/gui/widgets/skeletons/text_editor.cpp | 581 +++++++----------- 5 files changed, 302 insertions(+), 435 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 896027c0..b95b4fa7 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -85,6 +85,8 @@ namespace nana{ namespace widgets text_editor(window, graph_reference, const text_editor_scheme*); ~text_editor(); + size caret_size() const; + void set_highlight(const ::std::string& name, const ::nana::color&, const ::nana::color&); void erase_highlight(const ::std::string& name); void set_keyword(const ::std::wstring& kw, const std::string& name, bool case_sensitive, bool whole_word_matched); @@ -217,8 +219,10 @@ namespace nana{ namespace widgets std::vector _m_render_text(const ::nana::color& text_color); void _m_pre_calc_lines(std::size_t line_off, std::size_t lines); - ::nana::point _m_caret_to_screen(::nana::upoint pos) const; - ::nana::upoint _m_screen_to_caret(::nana::point pos) const; + //Caret to screen coordinate or context coordiate(in pixels) + ::nana::point _m_caret_to_coordinate(::nana::upoint pos, bool to_screen_coordinate = true) const; + //Screen coordinate or context coordinate(in pixels) to caret, + ::nana::upoint _m_coordinate_to_caret(::nana::point pos, bool from_screen_coordinate = true) const; bool _m_pos_from_secondary(std::size_t textline, const nana::upoint& secondary, unsigned & pos); bool _m_pos_secondary(const nana::upoint& charpos, nana::upoint& secondary_pos) const; @@ -243,8 +247,9 @@ namespace nana{ namespace widgets unsigned _m_tabs_pixels(size_type tabs) const; nana::size _m_text_extent_size(const char_type*, size_type n) const; - /// Moves the view of window. - bool _m_move_offset_x_while_over_border(int many); + /// Adjust position of view to make caret stay in screen + bool _m_adjust_view(); + bool _m_move_select(bool record_undo); int _m_text_top_base() const; diff --git a/include/nana/gui/widgets/skeletons/textbase.hpp b/include/nana/gui/widgets/skeletons/textbase.hpp index 55828351..751d9888 100644 --- a/include/nana/gui/widgets/skeletons/textbase.hpp +++ b/include/nana/gui/widgets/skeletons/textbase.hpp @@ -1,7 +1,7 @@ /* * A textbase class implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -44,7 +44,7 @@ namespace skeletons { attr_max_.reset(); //Insert an empty string for the first line of empty text. - text_cont_.emplace_back(); + text_cont_.emplace_back(new string_type); } void set_event_agent(textbase_event_agent_interface * evt) @@ -55,7 +55,7 @@ namespace skeletons bool empty() const { return (text_cont_.empty() || - ((text_cont_.size() == 1) && (text_cont_[0].empty()))); + ((text_cont_.size() == 1) && (text_cont_.front()->empty()))); } bool load(const char* file_utf8) @@ -135,10 +135,10 @@ namespace skeletons while(ifs.good()) { std::getline(ifs, str_mbs); - text_cont_.emplace_back(static_cast(nana::charset{ str_mbs })); - if(text_cont_.back().size() > attr_max_.size) + text_cont_.emplace_back(new string_type(static_cast(nana::charset{ str_mbs }))); + if(text_cont_.back()->size() > attr_max_.size) { - attr_max_.size = text_cont_.back().size(); + attr_max_.size = text_cont_.back()->size(); attr_max_.line = text_cont_.size() - 1; } } @@ -218,9 +218,9 @@ namespace skeletons byte_order_translate_4bytes(str); } - text_cont_.emplace_back(static_cast(nana::charset{ str, encoding })); + text_cont_.emplace_back(new string_type(static_cast(nana::charset{ str, encoding }))); - attr_max_.size = text_cont_.back().size(); + attr_max_.size = text_cont_.back()->size(); attr_max_.line = 0; } @@ -236,10 +236,10 @@ namespace skeletons byte_order_translate_4bytes(str); } - text_cont_.emplace_back(static_cast(nana::charset{ str, encoding })); - if(text_cont_.back().size() > attr_max_.size) + text_cont_.emplace_back(new string_type(static_cast(nana::charset{ str, encoding }))); + if(text_cont_.back()->size() > attr_max_.size) { - attr_max_.size = text_cont_.back().size(); + attr_max_.size = text_cont_.back()->size(); attr_max_.line = text_cont_.size() - 1; } } @@ -253,6 +253,9 @@ namespace skeletons std::ofstream ofs(to_osmbstr(fs), std::ios::binary); if(ofs && text_cont_.size()) { + auto i = text_cont_.cbegin(); + auto const count = text_cont_.size() - 1; + std::string last_mbs; if (is_unicode) @@ -272,32 +275,27 @@ namespace skeletons if (bytes) ofs.write(le_boms[static_cast(encoding)], bytes); - if (text_cont_.size() > 1) + for (std::size_t pos = 0; pos < count; ++pos) { - std::string mbs; - for (auto i = text_cont_.cbegin(), end = text_cont_.cend() - 1; i != end; ++i) - { - std::string(nana::charset(*i).to_bytes(encoding)).swap(mbs); - mbs += "\r\n"; - ofs.write(mbs.c_str(), static_cast(mbs.size())); - } + auto mbs = nana::charset(**(i++)).to_bytes(encoding); + ofs.write(mbs.c_str(), static_cast(mbs.size())); + ofs.write("\r\n", 2); } - last_mbs = nana::charset(text_cont_.back()).to_bytes(encoding); + last_mbs = nana::charset(*text_cont_.back()).to_bytes(encoding); } else { - if (text_cont_.size() > 1) + for (std::size_t pos = 0; pos < count; ++pos) { - for (auto i = text_cont_.cbegin(), end = text_cont_.cend() - 1; i != end; ++i) - { - std::string mbs = nana::charset(*i); - ofs.write(mbs.c_str(), mbs.size()); - ofs.write("\r\n", 2); - } + std::string mbs = nana::charset(**(i++)); + ofs.write(mbs.c_str(), mbs.size()); + ofs.write("\r\n", 2); } - last_mbs = nana::charset(text_cont_.back()); + + last_mbs = nana::charset(*text_cont_.back()); } + ofs.write(last_mbs.c_str(), static_cast(last_mbs.size())); _m_saved(std::move(fs)); } @@ -310,8 +308,8 @@ namespace skeletons const string_type& getline(size_type pos) const { - if(pos < text_cont_.size()) - return text_cont_[pos]; + if (pos < text_cont_.size()) + return *text_cont_[pos]; return nullstr_; } @@ -323,13 +321,13 @@ namespace skeletons public: void replace(size_type pos, string_type && text) { - if(text_cont_.size() <= pos) + if (text_cont_.size() <= pos) { - text_cont_.emplace_back(std::move(text)); + text_cont_.emplace_back(new string_type(std::move(text))); pos = text_cont_.size() - 1; } else - text_cont_[pos].swap(text); + _m_at(pos).swap(text); _m_make_max(pos); _m_edited(); @@ -339,7 +337,7 @@ namespace skeletons { if(pos.y < text_cont_.size()) { - string_type& lnstr = text_cont_[pos.y]; + string_type& lnstr = _m_at(pos.y); if(pos.x < lnstr.size()) lnstr.insert(pos.x, str); @@ -348,7 +346,7 @@ namespace skeletons } else { - text_cont_.emplace_back(std::move(str)); + text_cont_.emplace_back(new string_type(std::move(str))); pos.y = static_cast(text_cont_.size() - 1); } @@ -358,10 +356,10 @@ namespace skeletons void insertln(size_type pos, string_type&& str) { - if(pos < text_cont_.size()) - text_cont_.emplace(text_cont_.begin() + pos, std::move(str)); + if (pos < text_cont_.size()) + text_cont_.emplace(_m_iat(pos), new string_type(std::move(str))); else - text_cont_.emplace_back(std::move(str)); + text_cont_.emplace_back(new string_type(std::move(str))); _m_make_max(pos); _m_edited(); @@ -371,7 +369,7 @@ namespace skeletons { if (line < text_cont_.size()) { - string_type& lnstr = text_cont_[line]; + string_type& lnstr = _m_at(line); if ((pos == 0) && (count >= lnstr.size())) lnstr.clear(); else @@ -393,7 +391,7 @@ namespace skeletons if (pos + n > text_cont_.size()) n = text_cont_.size() - pos; - text_cont_.erase(text_cont_.begin() + pos, text_cont_.begin() + (pos + n)); + text_cont_.erase(_m_iat(pos), _m_iat(pos + n)); if (pos <= attr_max_.line && attr_max_.line < pos + n) _m_scan_for_max(); @@ -408,7 +406,7 @@ namespace skeletons { text_cont_.clear(); attr_max_.reset(); - text_cont_.emplace_back(); //text_cont_ must not be empty + text_cont_.emplace_back(new string_type); //text_cont_ must not be empty _m_saved(std::string()); } @@ -417,9 +415,14 @@ namespace skeletons { if(pos + 1 < text_cont_.size()) { - text_cont_[pos] += text_cont_[pos + 1]; - text_cont_.erase(text_cont_.begin() + (pos + 1)); + auto i = _m_iat(pos + 1); + _m_at(pos) += **i; + text_cont_.erase(i); _m_make_max(pos); + + //If the maxline is behind the pos line, + //decrease the maxline. Because a line between maxline and pos line + //has been deleted. if(pos < attr_max_.line) --attr_max_.line; @@ -458,9 +461,19 @@ namespace skeletons return edited() || filename_.empty(); } private: + string_type& _m_at(size_type pos) + { + return **_m_iat(pos); + } + + typename std::deque>::iterator _m_iat(size_type pos) + { + return text_cont_.begin() + pos; + } + void _m_make_max(std::size_t pos) { - const string_type& str = text_cont_[pos]; + const string_type& str = _m_at(pos); if(str.size() > attr_max_.size) { attr_max_.size = str.size(); @@ -472,11 +485,11 @@ namespace skeletons { attr_max_.size = 0; std::size_t n = 0; - for(auto & s : text_cont_) + for(auto & p : text_cont_) { - if(s.size() > attr_max_.size) + if(p->size() > attr_max_.size) { - attr_max_.size = s.size(); + attr_max_.size = p->size(); attr_max_.line = n; } ++n; @@ -514,7 +527,7 @@ namespace skeletons evt_agent_->text_changed(); } private: - std::deque text_cont_; + std::deque> text_cont_; textbase_event_agent_interface* evt_agent_{ nullptr }; mutable bool changed_{ false }; diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index 438ce4ea..4e92845b 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -319,31 +319,31 @@ namespace nana { void content_view::content_size(const size& sz, bool try_update) { + auto const view_sz = this->view_area(sz); + if (sz.height < impl_->content_size.height) { - if (impl_->origin.y + impl_->disp_area.height > sz.height) + if (impl_->origin.y + view_sz.height > sz.height) { - if (impl_->disp_area.height > sz.height) + if (view_sz.height > sz.height) impl_->origin.y = 0; else - impl_->origin.y = sz.height - impl_->disp_area.height; + impl_->origin.y = sz.height - view_sz.height; } } if (sz.width < impl_->content_size.width) { - if (impl_->origin.x + impl_->disp_area.width > sz.width) + if (impl_->origin.x + view_sz.width > sz.width) { - if (impl_->disp_area.width > sz.width) + if (view_sz.width > sz.width) impl_->origin.x = 0; else - impl_->origin.x = sz.width - impl_->disp_area.width; + impl_->origin.x = sz.width - view_sz.width; } } - impl_->content_size = sz; - impl_->size_changed(try_update); } @@ -388,18 +388,23 @@ namespace nana { rectangle content_view::view_area() const { - unsigned extra_horz = (impl_->disp_area.width < impl_->content_size.width ? space() : 0); - unsigned extra_vert = (impl_->disp_area.height < impl_->content_size.height + extra_horz ? space() : 0); + return view_area(impl_->content_size); + } + + rectangle content_view::view_area(const size& alt_content_size) const + { + unsigned extra_horz = (impl_->disp_area.width < alt_content_size.width ? space() : 0); + unsigned extra_vert = (impl_->disp_area.height < alt_content_size.height + extra_horz ? space() : 0); if ((0 == extra_horz) && extra_vert) - extra_horz = (impl_->disp_area.width < impl_->content_size.width + extra_vert ? space() : 0); + extra_horz = (impl_->disp_area.width < alt_content_size.width + extra_vert ? space() : 0); return rectangle{ impl_->disp_area.position(), size{ - impl_->disp_area.width > extra_vert ? impl_->disp_area.width - extra_vert : 0, - impl_->disp_area.height > extra_horz ? impl_->disp_area.height - extra_horz : 0 - } + impl_->disp_area.width > extra_vert ? impl_->disp_area.width - extra_vert : 0, + impl_->disp_area.height > extra_horz ? impl_->disp_area.height - extra_horz : 0 + } }; } diff --git a/source/gui/widgets/skeletons/content_view.hpp b/source/gui/widgets/skeletons/content_view.hpp index 6d4b2d40..ce2c60b7 100644 --- a/source/gui/widgets/skeletons/content_view.hpp +++ b/source/gui/widgets/skeletons/content_view.hpp @@ -65,6 +65,7 @@ namespace skeletons void draw_corner(graph_reference); rectangle view_area() const; + rectangle view_area(const size& alt_content_size) const; unsigned extra_space(bool horz) const; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index d008d70a..e81accb4 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -18,6 +18,7 @@ #include #include "content_view.hpp" +#include #include #include #include @@ -45,7 +46,7 @@ namespace nana{ namespace widgets { public: using command = EnumCommand; - using container = std::deque < std::unique_ptr> >; + using container = std::deque>>; void clear() { @@ -555,7 +556,6 @@ namespace nana{ namespace widgets virtual std::size_t take_lines() const = 0; /// Returns the number of lines that the line of text specified by pos takes. virtual std::size_t take_lines(std::size_t pos) const = 0; - virtual bool adjust_caret_into_screen() = 0; }; inline bool is_right_text(const unicode_bidi::entity& e) @@ -685,62 +685,6 @@ namespace nana{ namespace widgets { return 1; } - - //adjust_caret_into_screen - //@brief: Adjust the text offset in order to moving caret into visible area if it is out of the visible area - //@note: the function assumes the points_.caret is correct - bool adjust_caret_into_screen() override - { - const auto scrlines = editor_.screen_lines(); - if (0 == scrlines) - return false; - - auto const pre_origin = editor_.impl_->cview->origin(); - auto origin = pre_origin; - - auto& points = editor_.points_; - auto& textbase = editor_.textbase(); - - auto& lnstr = textbase.getline(points.caret.y); - const auto x = (std::min)(points.caret.x, static_cast(lnstr.size())); - auto const text_w = editor_._m_pixels_by_char(lnstr, x); - - auto area_w = editor_.impl_->cview->view_area().width; - - if (static_cast(text_w) < origin.x) - { - auto delta_pixels = editor_._m_text_extent_size(L" ", 4).width; - origin.x = (text_w > delta_pixels ? text_w - delta_pixels : 0); - } - else if (area_w && (text_w >= origin.x + area_w)) - origin.x = text_w - area_w + 2; - - int row = origin.y / static_cast(editor_.line_height()); - if (points.caret.y >= row + scrlines) //implicit condition scrlines > 0 - { - row = static_cast(points.caret.y - scrlines) + 1; - } - else if (static_cast(points.caret.y) < row) - { - if (scrlines >= static_cast(row)) - row = 0; - else - row = static_cast(row - scrlines); - } - else if (row && (textbase.lines() <= scrlines)) - row = 0; - - if(row != origin.y / static_cast(editor_.line_height())) - origin.y = row * editor_.line_height(); - - if (pre_origin != origin) - { - editor_.impl_->cview->move_origin(origin - pre_origin); - editor_.impl_->cview->sync(true); - return true; - } - return false; - } private: text_editor& editor_; std::vector sections_; @@ -773,9 +717,9 @@ namespace nana{ namespace widgets if ((0 == editor_.textbase().lines()) || (0 == line_px)) return coord; - auto screen_rows = (top - editor_.text_area_.area.y + editor_.impl_->cview->origin().y) / line_px; + auto text_row = (std::max)(0, (top - editor_.text_area_.area.y + editor_.impl_->cview->origin().y) / line_px); - coord = _m_textline(static_cast(screen_rows)); + coord = _m_textline(static_cast(text_row)); if (linemtr_.size() <= coord.first) { coord.first = linemtr_.size() - 1; @@ -795,22 +739,26 @@ namespace nana{ namespace widgets std::swap(first, second); if (second < linemtr_.size()) - linemtr_.erase(linemtr_.begin() + first + 1, linemtr_.begin() + second); + linemtr_.erase(linemtr_.begin() + first + 1, linemtr_.begin() + second + 1); - pre_calc_line(first, editor_.width_pixels()); + auto const width_px = editor_.width_pixels(); + pre_calc_line(first, width_px); + + /* //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. std::size_t line = 0; - for (auto & mtr: linemtr_) + for (auto & mtr: linemtr_) //deprecated { auto& linestr = editor_.textbase().getline(line); auto p = mtr.line_sections.front().begin; if (p < linestr.c_str() || (linestr.c_str() + linestr.size() < p)) - pre_calc_line(line, editor_.width_pixels()); + pre_calc_line(line, width_px); ++line; } + */ } void add_lines(std::size_t pos, std::size_t lines) override @@ -942,42 +890,6 @@ namespace nana{ namespace widgets { return (pos < linemtr_.size() ? linemtr_[pos].take_lines : 0); } - - bool adjust_caret_into_screen() override - { - const auto scrlines = editor_.screen_lines(); - if (0 == scrlines) - return false; - - const auto & points = editor_.points_; - auto off_coord = _m_textline(static_cast(editor_._m_text_topline())); - - nana::upoint caret_secondary; - editor_._m_pos_secondary(points.caret, caret_secondary); - - //Use the caret line for the offset line when caret is in front of current offset line. - if (off_coord.first > points.caret.y || ((off_coord.first == points.caret.y) && (off_coord.second > caret_secondary.y))) - { - //Use the line which was specified by points.caret for the first line. - _m_set_offset_by_secondary(row_coordinate(points.caret.y, caret_secondary.y)); - return true; - } - - //Find the last screen line. If the text does not reach the bottom of screen, - //do not adjust the offset line. - row_coordinate bottom; - if (false == _m_advance_secondary(off_coord, static_cast(scrlines - 1), bottom)) - return false; - - //Do not adjust the offset line if the caret line does not reach the bottom line. - if (points.caret.y < bottom.first || ((points.caret.y == bottom.first) && (caret_secondary.y <= bottom.second))) - return false; - - _m_advance_secondary(row_coordinate(points.caret.y, caret_secondary.y), -static_cast(scrlines - 1), bottom); - - _m_set_offset_by_secondary(bottom); - return true; - } private: void _m_text_section(const std::wstring& str, std::vector& tsec) { @@ -1014,90 +926,6 @@ namespace nana{ namespace widgets tsec.emplace_back(word, end, unsigned{}); } - void _m_set_offset_by_secondary(row_coordinate row) - { - for (auto i = linemtr_.begin(), end = linemtr_.begin() + row.first; i != end; ++i) - row.second += i->take_lines; - - auto origin = editor_.impl_->cview->origin(); - origin.y = static_cast(row.second * editor_.line_height()); - editor_.impl_->cview->move_origin(origin - editor_.impl_->cview->origin()); - } - - bool _m_advance_secondary(row_coordinate row, int distance, row_coordinate& new_row) - { - if ((row.first >= linemtr_.size()) || (row.second >= linemtr_[row.first].take_lines)) - return false; - - if (0 == distance) - { - new_row = row; - return true; - } - - if (distance < 0) - { - std::size_t n = static_cast(-distance); - - if (row.second > n) - { - new_row.first = row.first; - new_row.second = row.second - n; - return true; - } - - if (0 == row.first) - return false; - - --row.first; - n -= (row.second + 1); - - while (true) - { - auto lines = linemtr_[row.first].take_lines; - if (lines >= n) - { - new_row.first = row.first; - new_row.second = lines - n; - return true; - } - if (0 == row.first) - return false; - - --row.first; - n -= lines; - } - } - else - { - std::size_t n = static_cast(distance); - - auto delta_lines = linemtr_[row.first].take_lines - (row.second + 1); - - if (delta_lines >= n) - { - new_row.first = row.first; - new_row.second = row.second + n; - return true; - } - - n -= delta_lines; - - while (++row.first < linemtr_.size()) - { - auto & mtr = linemtr_[row.first]; - if (mtr.take_lines >= n) - { - new_row.first = row.first; - new_row.second = n - 1; - return true; - } - n -= mtr.take_lines; - } - } - return false; - } - row_coordinate _m_textline(std::size_t scrline) const { row_coordinate coord; @@ -1236,6 +1064,12 @@ namespace nana{ namespace widgets this->reset_caret(); }; + impl_->cview->events().hover_outside = [this](const point& pos) { + mouse_caret(pos, false); + if (selection::mode::mouse_selected == select_.mode_selection || selection::mode::method_selected == select_.mode_selection) + set_end_caret(false); + }; + API::create_caret(wd, { 1, line_height() }); API::bgcolor(wd, colors::white); API::fgcolor(wd, colors::black); @@ -1249,6 +1083,11 @@ namespace nana{ namespace widgets delete impl_; } + size text_editor::caret_size() const + { + return { 1, line_height() }; + } + void text_editor::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) { if (fgcolor.invisible() && bgcolor.invisible()) @@ -1680,7 +1519,7 @@ namespace nana{ namespace widgets API::set_capture(window_, true); text_area_.captured = true; - if (this->hit_select_area(_m_screen_to_caret(arg.pos), true)) + if (this->hit_select_area(_m_coordinate_to_caret(arg.pos), true)) { //The selected of text can be moved only if it is editable if (attributes_.editable) @@ -1732,7 +1571,7 @@ namespace nana{ namespace widgets //no move occurs select(false); - move_caret(_m_screen_to_caret(arg.pos)); + move_caret(_m_coordinate_to_caret(arg.pos)); } select_.mode_selection = selection::mode::no_selected; @@ -1798,7 +1637,8 @@ namespace nana{ namespace widgets if (graph_) { - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); + reset_caret(); impl_->try_refresh = sync_graph::refresh; points_.xpos = 0; @@ -1832,7 +1672,7 @@ namespace nana{ namespace widgets const unsigned line_pixels = line_height(); //The coordinate of caret - auto coord = _m_caret_to_screen(crtpos); + auto coord = _m_caret_to_coordinate(crtpos); const int line_bottom = coord.y + static_cast(line_pixels); @@ -1863,7 +1703,7 @@ namespace nana{ namespace widgets //Adjust the caret into screen when the caret position is modified by this function if (reset_caret && (!hit_text_area(coord))) { - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); impl_->try_refresh = sync_graph::refresh; caret->visible(true); return true; @@ -1949,7 +1789,7 @@ namespace nana{ namespace widgets select_.b = points_.caret; points_.xpos = points_.caret.x; - if(new_sel_end || (stay_in_view && impl_->capacities.behavior->adjust_caret_into_screen())) + if (new_sel_end || (stay_in_view && this->_m_adjust_view())) impl_->try_refresh = sync_graph::refresh; } @@ -1985,7 +1825,7 @@ namespace nana{ namespace widgets { points_.caret = select_.b; - if (impl_->capacities.behavior->adjust_caret_into_screen()) + if (this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; reset_caret(); @@ -1994,7 +1834,7 @@ namespace nana{ namespace widgets if (_m_move_select(true)) { - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); impl_->try_refresh = sync_graph::refresh; return true; } @@ -2117,7 +1957,8 @@ namespace nana{ namespace widgets if(graph_) { - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); + reset_caret(); impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(true); @@ -2269,7 +2110,8 @@ namespace nana{ namespace widgets } impl_->cview->move_origin(origin - impl_->cview->origin()); - if (impl_->capacities.behavior->adjust_caret_into_screen() || need_refresh) + + if (this->_m_adjust_view() || need_refresh) impl_->cview->sync(true); _m_reset_content_size(); @@ -2320,7 +2162,7 @@ namespace nana{ namespace widgets textbase.erase(points_.caret.y, points_.caret.x, erase_number); _m_pre_calc_lines(points_.caret.y, 1); - if(_m_move_offset_x_while_over_border(-2) == false) + if (!this->_m_adjust_view()) { _m_update_line(points_.caret.y, secondary); has_to_redraw = false; @@ -2349,11 +2191,11 @@ namespace nana{ namespace widgets if (record_undo) impl_->undo.push(std::move(undo_ptr)); - _m_reset_content_size(has_to_redraw); + _m_reset_content_size(false); if(has_to_redraw) { - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); impl_->try_refresh = sync_graph::refresh; } } @@ -2367,7 +2209,7 @@ namespace nana{ namespace widgets _m_reset_content_size(true); - impl_->capacities.behavior->adjust_caret_into_screen(); + this->_m_adjust_view(); impl_->try_refresh = sync_graph::refresh; } @@ -2391,10 +2233,8 @@ namespace nana{ namespace widgets if(points_.caret.x) { --points_.caret.x; - pending = false; - bool adjust_y = (attributes_.line_wrapped && impl_->capacities.behavior->adjust_caret_into_screen()); - if (_m_move_offset_x_while_over_border(-2) || adjust_y) + if (this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; } else if (points_.caret.y) //Move to previous line @@ -2403,7 +2243,7 @@ namespace nana{ namespace widgets pending = false; } - if (pending && impl_->capacities.behavior->adjust_caret_into_screen()) + if (pending && this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; points_.xpos = points_.caret.x; @@ -2412,25 +2252,23 @@ namespace nana{ namespace widgets void text_editor::move_right() { bool do_render = false; - if(_m_cancel_select(2) == false) + if (_m_cancel_select(2) == false) { auto lnstr = textbase().getline(points_.caret.y); - if(lnstr.size() > points_.caret.x) + if (lnstr.size() > points_.caret.x) { ++points_.caret.x; - - bool adjust_y = (attributes_.line_wrapped && impl_->capacities.behavior->adjust_caret_into_screen()); - do_render = (_m_move_offset_x_while_over_border(2) || adjust_y); + do_render = this->_m_adjust_view(); } - else if(points_.caret.y + 1 < textbase().lines()) + else if (points_.caret.y + 1 < textbase().lines()) { //Move to next line points_.caret.x = 0; - ++ points_.caret.y; - do_render = impl_->capacities.behavior->adjust_caret_into_screen(); + ++points_.caret.y; + do_render = this->_m_adjust_view(); } } else - do_render = impl_->capacities.behavior->adjust_caret_into_screen(); + do_render = this->_m_adjust_view(); if (do_render) impl_->try_refresh = sync_graph::refresh; @@ -2444,155 +2282,123 @@ namespace nana{ namespace widgets select_.a = select_.b = points_.caret; auto origin = impl_->cview->origin(); - origin.y = _m_text_topline(); + auto pos = points_.caret; + auto coord = _m_caret_to_coordinate(points_.caret, false); - bool changed = false; - nana::upoint caret = points_.caret; wchar_t key = arg.key; - size_t nlines = textbase().lines(); - if (arg.ctrl) { - switch (key) { - case keyboard::os_arrow_left: - case keyboard::os_arrow_right: - // TODO: move the caret word by word - break; - case keyboard::os_home: - if (caret.y != 0) { - caret.y = 0; - origin.y = 0; - changed = true; - } - break; - case keyboard::os_end: - if (caret.y != nlines - 1) { - caret.y = static_cast(nlines - 1); - changed = true; - } - break; - } - } - size_t lnsz = textbase().getline(caret.y).size(); + + auto const line_px = this->line_height(); + + //The number of text lines + auto const line_count = textbase().lines(); + + //The number of charecters in the line of caret + auto const text_length = textbase().getline(points_.caret.y).size(); + + switch (key) { case keyboard::os_arrow_left: if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift)) { - caret = select_.a; - changed = true; + pos = select_.a; } - else + else if (pos.x != 0) { - if (caret.x != 0) { - --caret.x; - changed = true; - } - else { - if (caret.y != 0) { - --caret.y; - caret.x = static_cast(textbase().getline(caret.y).size()); - changed = true; - } - } + --pos.x; + } + else if (pos.y != 0) { + --pos.y; + pos.x = static_cast(textbase().getline(pos.y).size()); } break; case keyboard::os_arrow_right: if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift)) { - caret = select_.b; - changed = true; + pos = select_.b; } - else + else if (pos.x < text_length) { - if (caret.x < lnsz) { - ++caret.x; - changed = true; - } - else { - if (caret.y != nlines - 1) { - ++caret.y; - caret.x = 0; - changed = true; - } - } + ++pos.x; + } + else if (pos.y != line_count - 1) + { + ++pos.y; + pos.x = 0; } break; case keyboard::os_arrow_up: + coord.y -= static_cast(line_px); + break; case keyboard::os_arrow_down: - { - auto screen_pt = _m_caret_to_screen(caret); - int offset = line_height(); - if (key == keyboard::os_arrow_up) { - offset = -offset; - } - screen_pt.y += offset; - - auto const new_caret = _m_screen_to_caret(screen_pt); - if (new_caret != caret) { - caret = new_caret; - if (screen_pt.y < 0) { - scroll(true, true); - } - changed = true; - } - } + coord.y += static_cast(line_px); break; case keyboard::os_home: - if (caret.x != 0) { - caret.x = 0; - changed = true; - } + //move the caret to the begining of the line + pos.x = 0; + + //move the caret to the begining of the text if Ctrl is pressed + if (arg.ctrl) + pos.y = 0; break; case keyboard::os_end: - if (caret.x < lnsz) { - caret.x = static_cast(lnsz); - changed = true; - } + //move the caret to the end of the line + pos.x = static_cast(text_length); + + //move the caret to the end of the text if Ctrl is pressed + if(arg.ctrl) + pos.y = (line_count - 1) * line_px; break; case keyboard::os_pageup: - if (caret.y >= screen_lines() && origin.y >= static_cast(screen_lines())) { - origin.y -= screen_lines(); - caret.y -= screen_lines(); - changed = true; + if(origin.y > 0) + { + auto off = coord - origin; + origin.y -= (std::min)(origin.y, static_cast(impl_->cview->view_area().height)); + coord = off + origin; } break; case keyboard::os_pagedown: - if (caret.y + screen_lines() <= impl_->capacities.behavior->take_lines()) { - origin.y += static_cast(screen_lines()); - caret.y += screen_lines(); - changed = true; + if (impl_->cview->content_size().height > impl_->cview->view_area().height) + { + auto off = coord - origin; + origin.y = (std::min)(origin.y + static_cast(impl_->cview->view_area().height), static_cast(impl_->cview->content_size().height - impl_->cview->view_area().height)); + coord = off + origin; } break; } - if (select_.a != caret || select_.b != caret) { - changed = true; + + if (pos == points_.caret) + { + impl_->cview->move_origin(origin - impl_->cview->origin()); + pos = _m_coordinate_to_caret(coord, false); } - if (changed) { + if (pos != points_.caret) { if (arg.shift) { switch (key) { case keyboard::os_arrow_left: case keyboard::os_arrow_up: case keyboard::os_home: case keyboard::os_pageup: - select_.b = caret; + select_.b = pos; break; case keyboard::os_arrow_right: case keyboard::os_arrow_down: case keyboard::os_end: case keyboard::os_pagedown: - select_.b = caret; + select_.b = pos; break; } - }else { - select_.b = caret; - select_.a = caret; } - points_.caret = caret; - - origin.y *= line_height(); - impl_->cview->move_origin(origin - impl_->cview->origin()); - impl_->cview->sync(true); + else { + select_.b = pos; + select_.a = pos; + } + points_.caret = pos; points_.xpos = points_.caret.x; impl_->try_refresh = sync_graph::refresh; + this->_m_adjust_view(); + impl_->cview->sync(true); + this->reset_caret(); } } @@ -2633,9 +2439,9 @@ namespace nana{ namespace widgets const upoint& text_editor::mouse_caret(const point& scrpos, bool stay_in_view) //From screen position { - points_.caret = _m_screen_to_caret(scrpos); + points_.caret = _m_coordinate_to_caret(scrpos); - if (stay_in_view && impl_->capacities.behavior->adjust_caret_into_screen()) + if (stay_in_view && this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; move_caret(points_.caret); @@ -2649,7 +2455,7 @@ namespace nana{ namespace widgets point text_editor::caret_screen_pos() const { - return _m_caret_to_screen(points_.caret); + return _m_caret_to_coordinate(points_.caret); } bool text_editor::scroll(bool upwards, bool vert) @@ -2667,7 +2473,7 @@ namespace nana{ namespace widgets { auto const height = line_height(); - auto top = _m_caret_to_screen(upoint{ 0, static_cast(row.first) }).y; + auto top = _m_caret_to_coordinate(upoint{ 0, static_cast(row.first) }).y; std::size_t lines = 1; if (whole_line) @@ -2751,7 +2557,7 @@ namespace nana{ namespace widgets this->impl_->capacities.behavior->pre_calc_line(pos, width_px); } - nana::point text_editor::_m_caret_to_screen(nana::upoint pos) const + nana::point text_editor::_m_caret_to_coordinate(nana::upoint pos, bool to_screen_coordinate) const { auto const behavior = impl_->capacities.behavior; auto const sections = behavior->line(pos.y); @@ -2759,7 +2565,7 @@ namespace nana{ namespace widgets std::size_t lines = 0; //lines before the caret line; for (std::size_t i = 0; i < pos.y; ++i) { - lines += behavior->line(i).size(); + lines += behavior->take_lines(i); } const text_section * sct_ptr = nullptr; @@ -2767,6 +2573,8 @@ namespace nana{ namespace widgets if (0 != pos.x) { std::wstring str; + + std::size_t sct_pos = 0; for (auto & sct : sections) { std::size_t chsize = sct.end - sct.begin; @@ -2776,7 +2584,9 @@ namespace nana{ namespace widgets else str.append(sct.begin, sct.end); - if (pos.x <= chsize) + //In line-wrapped mode. If the caret is at the end of a line which is not the last section, + //the caret should be moved to the beginning of next section line. + if ((sct_pos + 1 < sections.size()) ? (pos.x < chsize) : (pos.x <= chsize)) { sct_ptr = &sct; if (pos.x == chsize) @@ -2790,6 +2600,8 @@ namespace nana{ namespace widgets pos.x -= static_cast(chsize); ++lines; } + + ++sct_pos; } } @@ -2803,13 +2615,26 @@ namespace nana{ namespace widgets else scrpos.x += _m_text_x(*sct_ptr); - scrpos.y = static_cast(lines * line_height()) - impl_->cview->origin().y + this->_m_text_top_base(); + if (!to_screen_coordinate) + { + scrpos.y = static_cast(lines * line_height()); + //_m_text_x includes origin x and text_area x. remove these factors + scrpos.x += (impl_->cview->origin().x - text_area_.area.x); + + } + else + scrpos.y = static_cast(lines * line_height()) - impl_->cview->origin().y + this->_m_text_top_base(); + return scrpos; } - upoint text_editor::_m_screen_to_caret(point scrpos) const + upoint text_editor::_m_coordinate_to_caret(point scrpos, bool from_screen_coordinate) const { + if (!from_screen_coordinate) + scrpos -= (impl_->cview->origin() - point{ text_area_.area.x, this->_m_text_top_base() }); + auto const behavior = impl_->capacities.behavior; + auto const row = behavior->text_position_from_screen(scrpos.y); auto sections = behavior->line(row.first); @@ -2833,10 +2658,8 @@ namespace nana{ namespace widgets unicode_bidi{}.linestr(text_ptr, text_size, reordered); nana::upoint res(static_cast(real_str.begin - sections.front().begin), static_cast(row.first)); - scrpos.x -= _m_text_x(sections[row.second]); - if (scrpos.x < 0) - scrpos.x = 0; + scrpos.x = (std::max)(0, (scrpos.x - _m_text_x(sections[row.second]))); for (auto & ent : reordered) { @@ -2849,7 +2672,12 @@ namespace nana{ namespace widgets } scrpos.x -= str_px; } - res.x = static_cast(textbase().getline(res.y).size()); + + //move the caret to the end of this section. + res.x = text_size; + for (std::size_t i = 0; i < row.second; ++i) + res.x += static_cast(sections[i].end - sections[i].begin); + return res; } @@ -2939,7 +2767,7 @@ namespace nana{ namespace widgets } _m_pos_from_secondary(points_.caret.y, secondary_pos, points_.caret.x); - return behavior->adjust_caret_into_screen(); + return this->_m_adjust_view(); } void text_editor::_m_update_line(std::size_t pos, std::size_t secondary_count_before) @@ -2947,7 +2775,7 @@ namespace nana{ namespace widgets auto behavior = impl_->capacities.behavior; if (behavior->take_lines(pos) == secondary_count_before) { - auto top = _m_caret_to_screen(upoint{ 0, static_cast(pos) }).y; + auto top = _m_caret_to_coordinate(upoint{ 0, static_cast(pos) }).y; const unsigned pixels = line_height(); const rectangle update_area = { text_area_.area.x, top, width_pixels(), static_cast(pixels * secondary_count_before) }; @@ -3010,12 +2838,12 @@ namespace nana{ namespace widgets if (this->attributes_.line_wrapped) { + //detect if vertical scrollbar is required + auto const max_lines = screen_lines(true); + if (calc_lines) { - //detect if vertical scrollbar is required - auto const max_lines = screen_lines(true); auto text_lines = textbase().lines(); - if (text_lines <= max_lines) { std::size_t lines = 0; @@ -3034,11 +2862,12 @@ namespace nana{ namespace widgets //enable vertical scrollbar when text_lines > max_lines csize.width = _m_width_px(text_lines <= max_lines); - impl_->capacities.behavior->pre_calc_lines(csize.width); } else + { csize.width = impl_->cview->content_size().width; + } } else { @@ -3046,7 +2875,7 @@ namespace nana{ namespace widgets impl_->capacities.behavior->pre_calc_lines(0); auto maxline = textbase().max_line(); - csize.width = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second).width; + csize.width = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second).width + caret_size().width; } csize.height = static_cast(impl_->capacities.behavior->take_lines() * line_height()); @@ -3237,11 +3066,13 @@ namespace nana{ namespace widgets { case 1: points_.caret = a; - _m_move_offset_x_while_over_border(-2); + //_m_move_offset_x_while_over_border(-2); //deprecated + this->_m_adjust_view(); break; case 2: points_.caret = b; - _m_move_offset_x_while_over_border(2); + //_m_move_offset_x_while_over_border(2); //deprecated + this->_m_adjust_view(); break; } select_.a = select_.b = points_.caret; @@ -3271,50 +3102,63 @@ namespace nana{ namespace widgets return graph_.text_extent_size(str, static_cast(n)); } - //_m_move_offset_x_while_over_border - //@brief: Move the view window - bool text_editor::_m_move_offset_x_while_over_border(int many) + bool text_editor::_m_adjust_view() { - //x never beyonds border in line-wrapped mode. - if (attributes_.line_wrapped || (0 == many)) + auto const view_area = impl_->cview->view_area(); + + auto const line_px = static_cast(this->line_height()); + auto coord = _m_caret_to_coordinate(points_.caret, true); + + if (view_area.is_hit(coord) && view_area.is_hit({coord.x, coord.y + line_px})) return false; - const string_type& lnstr = textbase().getline(points_.caret.y); - unsigned width = _m_text_extent_size(lnstr.c_str(), points_.caret.x).width; + unsigned extra_count_horz = 4; + unsigned extra_count_vert = 0; - const auto count = static_cast(std::abs(many)); - if(many < 0) + auto const origin = impl_->cview->origin(); + coord = _m_caret_to_coordinate(points_.caret, false); + + point moved_origin; + + //adjust x-axis if it isn't line-wrapped mode + if (!attributes_.line_wrapped) { - auto origin = impl_->cview->origin(); + auto extra = points_.caret; - if (origin.x && (origin.x >= static_cast(width))) - { //Out of screen text area - if (points_.caret.x > count) - origin.x = static_cast(width - _m_text_extent_size(lnstr.c_str() + points_.caret.x - count, count).width); - else - origin.x = 0; - - impl_->cview->move_origin(origin - impl_->cview->origin()); - return true; + if (coord.x < origin.x) + { + extra.x -= (std::min)(extra_count_horz, points_.caret.x); + moved_origin.x = _m_caret_to_coordinate(extra, false).x - origin.x; + } + else if (coord.x + static_cast(caret_size().width) >= origin.x + static_cast(view_area.width)) + { + extra.x = (std::min)(textbase().getline(points_.caret.y).size(), points_.caret.x + extra_count_horz); + auto new_origin = _m_caret_to_coordinate(extra, false).x + static_cast(caret_size().width) - static_cast(view_area.width); + moved_origin.x = new_origin - origin.x; } } - else + + //upoint pos2nd; + //this->_m_pos_secondary(points_.caret, pos2nd); //deprecated + + auto extra_px = static_cast(line_px * extra_count_vert); + + if (coord.y < origin.y) { - auto const right_pos = impl_->cview->view_area().right(); - width += text_area_.area.x; + //Top of caret is less than the top of view - auto origin = impl_->cview->origin(); - if (static_cast(width) - origin.x >= right_pos) - { //Out of screen text area - origin.x = static_cast(width) - right_pos + 1; - auto rest_size = lnstr.size() - points_.caret.x; - origin.x += static_cast(_m_text_extent_size(lnstr.c_str() + points_.caret.x, (rest_size >= static_cast(many) ? static_cast(many) : rest_size)).width); - - impl_->cview->move_origin(origin - impl_->cview->origin()); - return true; - } + moved_origin.y = (std::max)(0, coord.y - extra_px) - origin.y; } - return false; + else if (coord.y + line_px >= origin.y + static_cast(view_area.height)) + { + //Bottom of caret is greater than the bottom of view + + auto const bottom = static_cast(impl_->capacities.behavior->take_lines() * line_px); + auto new_origin = (std::min)(coord.y + line_px + extra_px, bottom) - static_cast(view_area.height); + moved_origin.y = new_origin - origin.y; + } + + return impl_->cview->move_origin(moved_origin); } bool text_editor::_m_move_select(bool record_undo) @@ -3696,9 +3540,9 @@ namespace nana{ namespace widgets bool text_editor::_m_update_caret_line(std::size_t secondary_before) { - if (false == impl_->capacities.behavior->adjust_caret_into_screen()) + if(false == this->_m_adjust_view()) { - if (_m_caret_to_screen(points_.caret).x < impl_->cview->view_area().right()) + if (_m_caret_to_coordinate(points_.caret).x < impl_->cview->view_area().right()) { _m_update_line(points_.caret.y, secondary_before); return false; @@ -3789,4 +3633,3 @@ namespace nana{ namespace widgets }//end namespace skeletons }//end namespace widgets }//end namespace nana - From a5660773cb2fe4cc432f606435a4f40e679bda58 Mon Sep 17 00:00:00 2001 From: Yuchen Deng Date: Wed, 24 May 2017 21:24:29 +0800 Subject: [PATCH 07/28] Add '_d' suffix for debug library example for use: if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_link_libraries(${PROJECT_NAME} LINK_PRIVATE debug nana_d optimized nana) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries(${PROJECT_NAME} LINK_PRIVATE nana) endif() --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f0dc030..054137f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ endif() if(WIN32) add_definitions(-DWIN32) + set(CMAKE_DEBUG_POSTFIX "_d") #Global MSVC definitions. You may prefer the hand-tuned sln and projects from the nana repository. if(MSVC) option(MSVC_USE_MP "Set to ON to build nana with the /MP option (Visual Studio 2005 and above)." ON) From b3f1b259ab87108d97a58758f825ee485fc04db7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 25 May 2017 06:14:38 +0800 Subject: [PATCH 08/28] fix compiler error --- 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 e81accb4..6bf1bd52 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -3132,7 +3132,7 @@ namespace nana{ namespace widgets } else if (coord.x + static_cast(caret_size().width) >= origin.x + static_cast(view_area.width)) { - extra.x = (std::min)(textbase().getline(points_.caret.y).size(), points_.caret.x + extra_count_horz); + extra.x = (std::min)(static_cast(textbase().getline(points_.caret.y).size()), points_.caret.x + extra_count_horz); auto new_origin = _m_caret_to_coordinate(extra, false).x + static_cast(caret_size().width) - static_cast(view_area.width); moved_origin.x = new_origin - origin.x; } From 56e7f5ea4d5e267af509ab295077c7fa1ff77ab8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 27 May 2017 00:40:17 +0800 Subject: [PATCH 09/28] remove deprecated code --- .../gui/widgets/skeletons/text_editor.hpp | 1 - source/gui/widgets/skeletons/text_editor.cpp | 25 ------------------- 2 files changed, 26 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index b95b4fa7..664b07e7 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -321,7 +321,6 @@ namespace nana{ namespace widgets { nana::upoint caret; //position of caret by text, it specifies the position of a new character nana::upoint shift_begin_caret; - unsigned xpos{0}; //This data is used for move up/down }points_; }; }//end namespace skeletons diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 6bf1bd52..6f50cc83 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -744,21 +744,6 @@ namespace nana{ namespace widgets auto const width_px = editor_.width_pixels(); pre_calc_line(first, width_px); - - /* - //textbase is implement by using deque, and the linemtr holds the text pointers - //If the textbase is changed, it will check the text pointers. - std::size_t line = 0; - for (auto & mtr: linemtr_) //deprecated - { - auto& linestr = editor_.textbase().getline(line); - auto p = mtr.line_sections.front().begin; - if (p < linestr.c_str() || (linestr.c_str() + linestr.size() < p)) - pre_calc_line(line, width_px); - - ++line; - } - */ } void add_lines(std::size_t pos, std::size_t lines) override @@ -1641,7 +1626,6 @@ namespace nana{ namespace widgets reset_caret(); impl_->try_refresh = sync_graph::refresh; - points_.xpos = 0; //_m_put calcs the lines _m_reset_content_size(false); @@ -1787,7 +1771,6 @@ namespace nana{ namespace widgets { bool new_sel_end = (select_.b != points_.caret); select_.b = points_.caret; - points_.xpos = points_.caret.x; if (new_sel_end || (stay_in_view && this->_m_adjust_view())) impl_->try_refresh = sync_graph::refresh; @@ -1962,7 +1945,6 @@ namespace nana{ namespace widgets reset_caret(); impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(true); - points_.xpos = points_.caret.x; } } @@ -1997,7 +1979,6 @@ namespace nana{ namespace widgets impl_->try_refresh = sync_graph::refresh; _m_reset_content_size(); - points_.xpos = points_.caret.x; } void text_editor::copy() const @@ -2139,7 +2120,6 @@ namespace nana{ namespace widgets if(has_erase) backspace(); _m_reset_content_size(); - points_.xpos = points_.caret.x; } void text_editor::backspace(bool record_undo) @@ -2245,8 +2225,6 @@ namespace nana{ namespace widgets if (pending && this->_m_adjust_view()) impl_->try_refresh = sync_graph::refresh; - - points_.xpos = points_.caret.x; } void text_editor::move_right() @@ -2272,8 +2250,6 @@ namespace nana{ namespace widgets if (do_render) impl_->try_refresh = sync_graph::refresh; - - points_.xpos = points_.caret.x; } void text_editor::_m_handle_move_key(const arg_keyboard& arg) @@ -2394,7 +2370,6 @@ namespace nana{ namespace widgets select_.a = pos; } points_.caret = pos; - points_.xpos = points_.caret.x; impl_->try_refresh = sync_graph::refresh; this->_m_adjust_view(); impl_->cview->sync(true); From 39142e18be397b685f75d03c3e2c5e4c4dca890a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 27 May 2017 00:42:48 +0800 Subject: [PATCH 10/28] remove deprecated code --- source/gui/widgets/listbox.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1b33d880..3aa2262f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2248,7 +2248,6 @@ namespace nana if (seq.empty()) return 0; - //return (header.position(seq[0], nullptr) - this->content_view->origin().x + r.x); //deprecated return header.range(seq.front()).first + r.x - this->content_view->origin().x; } @@ -3226,14 +3225,10 @@ namespace nana auto i = essence_->header.column_from_point(x); if (i == npos) - //i = essence_->header.boundary(essence_->header.position(grab, nullptr) >= x); //deprecated i = essence_->header.boundary(essence_->header.range(grab).first >= x); if(grab != i) { - //unsigned item_pixels = 0; - //auto item_x = essence_->header.position(i, &item_pixels); //deprecated - auto item_rg = essence_->header.range(i); //Get the item pos @@ -3319,7 +3314,6 @@ namespace nana _m_draw_header_item(fl_graph, margin, rectangle{ fl_graph.size()}, colors::white, col, item_state::floated); - //auto xpos = essence_->header.position(col.index, nullptr) + pos.x - grabs_.start_pos; //deprecated auto xpos = essence_->header.range(col.index).first + pos.x - grabs_.start_pos; essence_->graph->blend(rectangle{ point{ xpos - essence_->content_view->origin().x + rect.x, rect.y } , fl_graph.size() }, fl_graph, {}, 0.5); } @@ -3405,7 +3399,6 @@ namespace nana auto & ptr_where = essence_->pointer_where; - //int item_top = rect.y - (origin.y % item_height_px); //deprecated auto first_disp = essence_->first_display(); point item_coord{ @@ -3444,8 +3437,6 @@ namespace nana ind->detach(); } - //const int x = essence_->item_xpos(rect); //deprecated - //Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos)) if (idx.cat == 0 || !idx.is_category()) { @@ -3579,7 +3570,6 @@ namespace nana //Draw selecting inner rectangle if (item.flags.selected && (categ.expand == false)) - //_m_draw_item_border(r.x, y, (std::min)(r.width, width - essence_->content_view->origin().x)); //deprecated _m_draw_item_border(y); } @@ -3816,7 +3806,6 @@ namespace nana //Draw selecting inner rectangle if (item.flags.selected) - //_m_draw_item_border(content_r.x, coord.y, show_w); //deprecated _m_draw_item_border(coord.y); } From a92b3e4274a183fe85015530b208ef9e2d88e47a Mon Sep 17 00:00:00 2001 From: Leonardo Backes Vargas Date: Sun, 28 May 2017 12:16:26 -0300 Subject: [PATCH 11/28] Fix constness on const functions with nana::any and related casts. --- include/nana/gui/widgets/listbox.hpp | 2 +- include/nana/gui/widgets/tabbar.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index f3cc09df..552b2e36 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -893,7 +893,7 @@ namespace nana } template - T* value_ptr() const + T const * value_ptr() const { return any_cast(_m_value()); } diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index f22e6e5c..0e2e2e9c 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -237,9 +237,9 @@ namespace nana return this->get_drawer_trigger().activated(); } - value_type & at(std::size_t pos) const /// Returns pos'th element + value_type const & at(std::size_t pos) const /// Returns pos'th element { - return static_cast(this->get_drawer_trigger().at(pos)); + return any_cast(this->get_drawer_trigger().at(pos)); } void close_fly(bool fly) /// Draw or not a close button in each tab. From 2f21c33392619b48a1f832c5fa69c03ce2540d5a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 30 May 2017 04:50:10 +0800 Subject: [PATCH 12/28] remove deprecated code --- .../gui/widgets/skeletons/text_editor.hpp | 1 - source/gui/widgets/skeletons/text_editor.cpp | 44 ++++++------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 664b07e7..49bb0867 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -244,7 +244,6 @@ namespace nana{ namespace widgets static bool _m_resolve_text(const ::std::wstring&, std::vector> & lines); bool _m_cancel_select(int align); - unsigned _m_tabs_pixels(size_type tabs) const; nana::size _m_text_extent_size(const char_type*, size_type n) const; /// Adjust position of view to make caret stay in screen diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 6f50cc83..dda5d25b 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1969,6 +1969,7 @@ namespace nana{ namespace widgets points_.caret.x ++; + _m_reset_content_size(); if (!refresh) { @@ -1978,7 +1979,6 @@ namespace nana{ namespace widgets else impl_->try_refresh = sync_graph::refresh; - _m_reset_content_size(); } void text_editor::copy() const @@ -2590,15 +2590,15 @@ namespace nana{ namespace widgets else scrpos.x += _m_text_x(*sct_ptr); + scrpos.y = static_cast(lines * line_height()); + if (!to_screen_coordinate) { - scrpos.y = static_cast(lines * line_height()); //_m_text_x includes origin x and text_area x. remove these factors scrpos.x += (impl_->cview->origin().x - text_area_.area.x); - } else - scrpos.y = static_cast(lines * line_height()) - impl_->cview->origin().y + this->_m_text_top_base(); + scrpos.y += this->_m_text_top_base() - impl_->cview->origin().y; return scrpos; } @@ -2641,8 +2641,7 @@ namespace nana{ namespace widgets auto str_px = static_cast(_m_text_extent_size(ent.begin, ent.end - ent.begin).width); if (scrpos.x <= str_px) { - res.x += _m_char_by_pixels(ent, scrpos.x); - res.x += static_cast(ent.begin - text_ptr); + res.x += _m_char_by_pixels(ent, scrpos.x) + static_cast(ent.begin - text_ptr); return res; } scrpos.x -= str_px; @@ -2942,11 +2941,12 @@ namespace nana{ namespace widgets std::wstring text_editor::_m_make_select_string() const { std::wstring text; - + nana::upoint a, b; if (get_selected_points(a, b)) { auto & textbase = this->textbase(); + if (a.y != b.y) { text = textbase.getline(a.y).substr(a.x); @@ -2959,7 +2959,7 @@ namespace nana{ namespace widgets text += textbase.getline(b.y).substr(0, b.x); } else - text = textbase.getline(a.y).substr(a.x, b.x - a.x); + return textbase.getline(a.y).substr(a.x, b.x - a.x); } return text; @@ -3034,22 +3034,16 @@ namespace nana{ namespace widgets bool text_editor::_m_cancel_select(int align) { - nana::upoint a, b; + upoint a, b; if (get_selected_points(a, b)) { - switch(align) + //domain of algin = [0, 2] + if (align) { - case 1: - points_.caret = a; - //_m_move_offset_x_while_over_border(-2); //deprecated + this->points_.caret = (1 == align ? a : b); this->_m_adjust_view(); - break; - case 2: - points_.caret = b; - //_m_move_offset_x_while_over_border(2); //deprecated - this->_m_adjust_view(); - break; } + select_.a = select_.b = points_.caret; reset_caret(); return true; @@ -3057,15 +3051,6 @@ namespace nana{ namespace widgets return false; } - unsigned text_editor::_m_tabs_pixels(size_type tabs) const - { - if(0 == tabs) return 0; - - wchar_t ws[2] = {}; - ws[0] = mask_char_ ? mask_char_ : ' '; - return static_cast(tabs * graph_.text_extent_size(ws).width * text_area_.tab_space); - } - nana::size text_editor::_m_text_extent_size(const char_type* str, size_type n) const { if(mask_char_) @@ -3113,9 +3098,6 @@ namespace nana{ namespace widgets } } - //upoint pos2nd; - //this->_m_pos_secondary(points_.caret, pos2nd); //deprecated - auto extra_px = static_cast(line_px * extra_count_vert); if (coord.y < origin.y) From 5746fc33f6333d1dab1f229a98f6d716b53fdad0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 30 May 2017 10:43:10 +0800 Subject: [PATCH 13/28] fix bug of text_editor scrollbar --- source/gui/widgets/skeletons/content_view.cpp | 21 ++++++++++--------- source/gui/widgets/skeletons/content_view.hpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 10 +++++++-- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index 4e92845b..8995944a 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -30,7 +30,8 @@ namespace nana { point skew_vert; nana::size extra_px; - bool enable_update{ true }; + bool passive{ true }; //The passive mode determines whether to update if scrollbar changes. It updates the client window if passive is true. + bool drag_started{ false }; point origin; @@ -171,7 +172,7 @@ namespace nana { }); } - void size_changed(bool try_update) + void size_changed(bool passive) { auto imd_area = view.view_area(); @@ -186,11 +187,11 @@ namespace nana { if (this->events.scrolled) this->events.scrolled(); - if (this->enable_update) + if (this->passive) API::refresh_window(this->window_handle); }; - this->enable_update = try_update; + this->passive = passive; if (imd_area.width != disp_area.width) { @@ -199,7 +200,7 @@ namespace nana { vert.create(window_handle); vert.events().value_changed.connect_unignorable(event_fn); API::take_active(vert, false, window_handle); - this->enable_update = false; + this->passive = false; } vert.move({ @@ -226,7 +227,7 @@ namespace nana { horz.create(window_handle); horz.events().value_changed.connect_unignorable(event_fn); API::take_active(horz, false, window_handle); - this->enable_update = false; + this->passive = false; } horz.move({ @@ -246,7 +247,7 @@ namespace nana { origin.x = 0; } - this->enable_update = true; + this->passive = true; } }; @@ -462,12 +463,12 @@ namespace nana { return (pre_origin != impl_->origin); } - void content_view::sync(bool try_update) + void content_view::sync(bool passive) { - impl_->enable_update = try_update; + impl_->passive = passive; impl_->horz.value(impl_->origin.x); impl_->vert.value(impl_->origin.y); - impl_->enable_update = true; + impl_->passive = true; } void content_view::pursue(const point& cursor) diff --git a/source/gui/widgets/skeletons/content_view.hpp b/source/gui/widgets/skeletons/content_view.hpp index ce2c60b7..9abd59a4 100644 --- a/source/gui/widgets/skeletons/content_view.hpp +++ b/source/gui/widgets/skeletons/content_view.hpp @@ -74,7 +74,7 @@ namespace skeletons /// Returns true if the origin is moved bool move_origin(const point& skew); - void sync(bool try_update); + void sync(bool passive); void pursue(const point& cursor); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index dda5d25b..3129d71c 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1938,13 +1938,14 @@ namespace nana{ namespace widgets impl_->undo.push(std::move(undo_ptr)); + _m_reset_content_size(true); + if(graph_) { this->_m_adjust_view(); reset_caret(); impl_->try_refresh = sync_graph::refresh; - _m_reset_content_size(true); } } @@ -3497,7 +3498,7 @@ namespace nana{ namespace widgets bool text_editor::_m_update_caret_line(std::size_t secondary_before) { - if(false == this->_m_adjust_view()) + if (false == this->_m_adjust_view()) { if (_m_caret_to_coordinate(points_.caret).x < impl_->cview->view_area().right()) { @@ -3505,6 +3506,11 @@ namespace nana{ namespace widgets return false; } } + else + { + //The content view is adjusted, now syncs it with active mode to avoid updating. + impl_->cview->sync(false); + } impl_->try_refresh = sync_graph::refresh; return true; } From a87703d418f263c4068ef3efeec09d580404f602 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 31 May 2017 22:36:56 +0800 Subject: [PATCH 14/28] refactor functions --- include/nana/unicode_bidi.hpp | 7 +- source/gui/detail/bedrock_pi.cpp | 2 +- source/gui/detail/window_manager.cpp | 12 +-- source/gui/widgets/label.cpp | 4 +- source/gui/widgets/listbox.cpp | 58 ++++-------- source/gui/widgets/skeletons/text_editor.cpp | 54 +++++------ source/paint/graphics.cpp | 9 +- source/paint/text_renderer.cpp | 96 +++++++++++--------- source/unicode_bidi.cpp | 22 +++-- 9 files changed, 121 insertions(+), 143 deletions(-) diff --git a/include/nana/unicode_bidi.hpp b/include/nana/unicode_bidi.hpp index 71a5f882..72d65860 100644 --- a/include/nana/unicode_bidi.hpp +++ b/include/nana/unicode_bidi.hpp @@ -49,7 +49,7 @@ namespace nana unsigned level; }; - void linestr(const char_type*, std::size_t len, std::vector & reordered); + std::vector reorder(const char_type*, std::size_t len); private: static unsigned _m_paragraph_level(const char_type * begin, const char_type * end); @@ -65,13 +65,12 @@ namespace nana void _m_reordering_resolved_levels(std::vector & reordered); static bidi_category _m_bidi_category(bidi_char); static bidi_char _m_char_dir(char_type); - private: - void _m_output_levels() const; - void _m_output_bidi_char() const; private: std::vector levels_; }; + std::vector unicode_reorder(const wchar_t* text, std::size_t length); + } #include diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index ca36a92f..294c56f9 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -131,7 +131,7 @@ namespace nana if (((0 == thread_id) || (wd->thread_id == thread_id)) && (wd->root != root)) { root = wd->root; - if (roots.cend() == std::find(roots.cbegin(), roots.cend(), root)) + if (roots.end() == std::find(roots.begin(), roots.end(), root)) roots.emplace_back(root); } } diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 7a8980e8..6d1ce3ca 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1397,14 +1397,14 @@ namespace detail { auto & tabs = wd->root_widget->other.attribute.root->tabstop; - auto end = tabs.cend(); + auto end = tabs.end(); if (forward) { if (detail::tab_type::none == wd->flags.tab) return (tabs.front()); else if (detail::tab_type::tabstop & wd->flags.tab) { - auto i = std::find(tabs.cbegin(), end, wd); + auto i = std::find(tabs.begin(), end, wd); if (i != end) { ++i; @@ -1417,9 +1417,9 @@ namespace detail } else if (tabs.size() > 1) //at least 2 elments in tabs are required when moving backward. { - auto i = std::find(tabs.cbegin(), end, wd); + auto i = std::find(tabs.begin(), end, wd); if (i != end) - return (tabs.cbegin() == i ? tabs.back() : *(i - 1)); + return (tabs.begin() == i ? tabs.back() : *(i - 1)); } return nullptr; } @@ -1549,7 +1549,7 @@ namespace detail for (auto child : wd->children) { auto child_keys = shortkeys(child, true); - std::copy(child_keys.cbegin(), child_keys.cend(), std::back_inserter(result)); + std::copy(child_keys.begin(), child_keys.end(), std::back_inserter(result)); } } } @@ -1716,7 +1716,7 @@ namespace detail if (pa_children.size() > 1) { - for (auto i = pa_children.cbegin(), end = pa_children.cend(); i != end; ++i) + for (auto i = pa_children.begin(), end = pa_children.end(); i != end; ++i) { if (((*i)->index) > (wd->index)) { diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index a4a8cef1..1d436f68 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -519,9 +519,7 @@ namespace nana void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs) { - nana::unicode_bidi bidi; - std::vector reordered; - bidi.linestr(s.data(), s.length(), reordered); + auto const reordered = unicode_reorder(s.data(), s.length()); pixel_tag px = rs.pixels[rs.index]; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3aa2262f..cc32afac 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -332,7 +332,8 @@ namespace nana unsigned ranged_px = 0; unsigned ranged_count = 0; - for (auto & col : cont_) + auto const & const_cont = cont_; + for (auto & col : const_cont) { if (col.visible_state) { @@ -486,27 +487,6 @@ namespace nana return{ left, 0 }; } - /* - /// Returns the left point position and width(in variable *pixels) of column originaly at position pos. - int position(size_type pos, unsigned * pixels) const - { - int left = 0; - for (auto & m : cont_) - { - if (m.index == pos) - { - if (pixels) - *pixels = m.width_px; - break; - } - - if (m.visible_state) - left += m.width_px; - } - return left; - } - */ - /// return the original index of the visible col currently before(in front of) or after the col originaly at index "index" size_type next(size_type index) const noexcept { @@ -548,11 +528,15 @@ namespace nana if ((from == to) || (from >= cont_.size()) || (to >= cont_.size())) return; +#ifdef _MSC_VER + for (auto i = cont_.cbegin(); i != cont_.cend(); ++i) +#else for (auto i = cont_.begin(); i != cont_.end(); ++i) +#endif { if (from == i->index) { - auto col_from = std::move(*i); + auto col_from = *i; cont_.erase(i); //A workaround for old libstdc++, that some operations of vector @@ -781,19 +765,6 @@ namespace nana std::string to_string(const export_options& exp_opt) const; - std::vector get_inline_pane(const index_pair& item_pos) - { - std::vector panes; - for (auto p : active_panes_) - { - if (p && (p->item_pos == item_pos)) - { - panes.emplace_back(p); - } - } - return panes; - } - void emit_cs(const index_pair& pos, bool for_selection) { item_proxy i(ess_, pos); @@ -806,13 +777,16 @@ namespace nana else events.checked.emit(arg, wd_ptr()->handle()); - auto panes = get_inline_pane(pos); - for (auto p : panes) + //notify the inline pane. An item may have multiple panes, each pane is for a column. + for (auto p : active_panes_) { - if(for_selection) - p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); - else - p->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + if (p && (p->item_pos == pos)) + { + if (for_selection) + p->inline_ptr->notify_status(inline_widget_status::selecting, i.selected()); + else + p->inline_ptr->notify_status(inline_widget_status::checking, i.checked()); + } } } diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 3129d71c..f1076238 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -407,11 +407,11 @@ namespace nana{ namespace widgets std::shared_ptr find(std::size_t pos) const { - for (auto i = colored_areas_.cbegin(); i != colored_areas_.cend(); ++i) + for (auto & sp : colored_areas_) { - if (i->get()->begin <= pos && pos < i->get()->begin + i->get()->count) - return *i; - else if (i->get()->begin > pos) + if (sp->begin <= pos && pos < sp->begin + sp->count) + return sp; + else if (sp->begin > pos) break; } return{}; @@ -623,7 +623,9 @@ namespace nana{ namespace widgets //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. std::size_t line = 0; - for (auto & sct : this->sections_) + + auto const & const_sections = sections_; + for (auto & sct : const_sections) { auto const& text = editor_.textbase().getline(line); if (sct.begin < text.c_str() || (text.c_str() + text.size() < sct.begin)) @@ -646,7 +648,9 @@ namespace nana{ namespace widgets //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. std::size_t line = 0; - for (auto & sct : this->sections_) + + auto const & const_sections = sections_; + for (auto & sct : const_sections) { if (line < pos || (pos + line_size) <= line) { @@ -664,8 +668,8 @@ namespace nana{ namespace widgets auto const & text = editor_.textbase().getline(pos); auto& txt_section = this->sections_[pos]; txt_section.begin = text.c_str(); - txt_section.end = text.c_str() + text.size(); - txt_section.pixels = editor_._m_text_extent_size(text.c_str(), text.size()).width; + txt_section.end = txt_section.begin + text.size(); + txt_section.pixels = editor_._m_text_extent_size(txt_section.begin, text.size()).width; } void pre_calc_lines(unsigned) override @@ -756,7 +760,9 @@ namespace nana{ namespace widgets //textbase is implement by using deque, and the linemtr holds the text pointers //If the textbase is changed, it will check the text pointers. std::size_t line = 0; - for (auto & mtr : linemtr_) + + auto const & const_linemtr = linemtr_; + for (auto & mtr : const_linemtr) { if (line < pos || (pos + lines) <= line) { @@ -2031,11 +2037,9 @@ namespace nana{ namespace widgets return; auto undo_ptr = std::unique_ptr(new undo_input_text(*this, std::wstring(1, '\n'))); - bool need_refresh = (select_.a != select_.b); undo_ptr->set_selected_text(); - if(need_refresh) - points_.caret = _m_erase_select(); + points_.caret = _m_erase_select(); undo_ptr->set_caret_pos(); @@ -2067,12 +2071,7 @@ namespace nana{ namespace widgets points_.caret.x = 0; auto origin = impl_->cview->origin(); - if (origin.x || (points_.caret.y < textbase.lines()) || textbase.getline(points_.caret.y).size()) - { - origin.x = -origin.x; - impl_->cview->move_origin(origin); - need_refresh = true; - } + origin.x = 0; if (impl_->indent.enabled) { @@ -2090,13 +2089,13 @@ namespace nana{ namespace widgets put(text); } } + else + _m_reset_content_size(); - impl_->cview->move_origin(origin - impl_->cview->origin()); + auto origin_moved = impl_->cview->move_origin(origin - impl_->cview->origin()); - if (this->_m_adjust_view() || need_refresh) + if (this->_m_adjust_view() || origin_moved) impl_->cview->sync(true); - - _m_reset_content_size(); } void text_editor::del() @@ -2630,8 +2629,7 @@ namespace nana{ namespace widgets text_ptr = mask_str.c_str(); } - std::vector reordered; - unicode_bidi{}.linestr(text_ptr, text_size, reordered); + auto const reordered = unicode_reorder(text_ptr, text_size); nana::upoint res(static_cast(real_str.begin - sections.front().begin), static_cast(row.first)); @@ -3333,8 +3331,7 @@ namespace nana{ namespace widgets const auto focused = API::is_focus_ready(window_); - std::vector reordered; - unicode_bidi{}.linestr(text_ptr, text_len, reordered); + auto const reordered = unicode_reorder(text_ptr, text_len); //Parse highlight keywords keyword_parser parser; @@ -3564,9 +3561,8 @@ namespace nana{ namespace widgets if (pos > lnstr.size()) return 0; - std::vector reordered; - unicode_bidi{}.linestr(lnstr.c_str(), lnstr.size(), reordered); - + auto const reordered = unicode_reorder(lnstr.c_str(), lnstr.size()); + auto target = lnstr.c_str() + pos; unsigned text_w = 0; diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index b3bedd40..075f8be1 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -509,9 +509,7 @@ namespace paint nana::size sz; if(impl_->handle && impl_->handle->context && str.size()) { - std::vector reordered; - unicode_bidi bidi; - bidi.linestr(str.c_str(), str.size(), reordered); + auto const reordered = unicode_reorder(str.c_str(), str.size()); for(auto & i: reordered) { nana::size t = text_extent_size(i.begin, i.end - i.begin); @@ -958,9 +956,8 @@ namespace paint unsigned graphics::bidi_string(const nana::point& pos, const wchar_t * str, std::size_t len) { auto moved_pos = pos; - unicode_bidi bidi; - std::vector reordered; - bidi.linestr(str, len, reordered); + + auto const reordered = unicode_reorder(str, len); for (auto & i : reordered) { string(moved_pos, i.begin, i.end - i.begin); diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index af206d40..07b71e0f 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -13,26 +13,23 @@ namespace nana template void for_each_line(const wchar_t * str, std::size_t len, int top, F & f) { - auto head = str; - auto end = str + len; + auto const end = str + len; for(auto i = str; i != end; ++i) { if(*i == '\n') { - top += static_cast(f(top, head, i - head)); - head = i + 1; + top += static_cast(f(top, str, i - str)); + str = i + 1; } } - if(head != end) - f(top, head, end - head); + if(str != end) + f(top, str, end - str); } struct draw_string { drawable_type dw; const int x, endpos; - nana::unicode_bidi bidi; - std::vector reordered; align text_align; draw_string(drawable_type dw, int x, int endpos, align ta) @@ -41,9 +38,13 @@ namespace nana unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { + auto const reordered = unicode_reorder(buf, bufsize); + if (reordered.empty()) + return 0; + nana::point pos{ x, top }; unsigned pixels = 0; - bidi.linestr(buf, bufsize, reordered); + switch(text_align) { case align::left: @@ -64,23 +65,28 @@ namespace nana case align::center: { unsigned lenpx = 0; - std::vector widths; + std::unique_ptr entity_pxs(new unsigned[reordered.size()]); + + auto ent_px = entity_pxs.get(); + for(auto & ent : reordered) { auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin); if(ts.height > pixels) pixels = ts.height; lenpx += ts.width; - widths.emplace_back(ts.width); + *ent_px++ = ts.width; } pos.x += (endpos - pos.x - static_cast(lenpx))/2; - auto ipx = widths.begin(); + ent_px = entity_pxs.get(); + for(auto & ent : reordered) { - if(pos.x + static_cast(*ipx) > 0) + if (pos.x + static_cast(*ent_px) > 0) detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - pos.x += static_cast(*ipx); + pos.x += static_cast(*ent_px++); + if(pos.x >= endpos) break; } @@ -90,7 +96,7 @@ namespace nana { int xend = endpos; std::swap(pos.x, xend); - for(auto i = reordered.rbegin(), end = reordered.rend(); i != end; ++i) + for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) { auto & ent = *i; std::size_t len = ent.end - ent.begin; @@ -118,13 +124,11 @@ namespace nana graphics & graph; int x, endpos; unsigned omitted_pixels; - nana::unicode_bidi bidi; - std::vector reordered; draw_string_omitted(graphics& graph, int x, int endpos, bool omitted) : graph(graph), x(x), endpos(endpos) { - omitted_pixels = (omitted ? graph.text_extent_size(L"...", 3).width : 0); + omitted_pixels = (omitted ? graph.text_extent_size("...", 3).width : 0); if (endpos - x > static_cast(omitted_pixels)) this->endpos -= omitted_pixels; else @@ -136,7 +140,9 @@ namespace nana drawable_type dw = graph.handle(); ::nana::point pos{ x, top }; unsigned pixels = 0; - bidi.linestr(buf, bufsize, reordered); + + auto const reordered = unicode_reorder(buf, bufsize); + for(auto & i : reordered) { std::size_t len = i.end - i.begin; @@ -178,9 +184,6 @@ namespace nana { graphics & graph; int x, endpos; - nana::unicode_bidi bidi; - std::vector reordered; - std::vector ts_keeper; align text_align; draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta) @@ -191,10 +194,13 @@ namespace nana { unsigned pixels = 0; - drawable_type dw = graph.handle(); + auto const dw = graph.handle(); unsigned str_w = 0; - ts_keeper.clear(); - bidi.linestr(buf, bufsize, reordered); + + std::vector ts_keeper; + + auto const reordered = unicode_reorder(buf, bufsize); + for(auto & i : reordered) { nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); @@ -213,28 +219,33 @@ namespace nana auto i_ts_keeper = ts_keeper.cbegin(); for(auto & i : reordered) { - if(line_pixels < i_ts_keeper->height) + if(line_pixels < i_ts_keeper->height) line_pixels = i_ts_keeper->height; bool beyond_edge = (pos.x + static_cast(i_ts_keeper->width) > endpos); if(beyond_edge) { - std::size_t len = i.end - i.begin; + const std::size_t len = i.end - i.begin; if(len > 1) { - unsigned * pxbuf = new unsigned[len]; + std::unique_ptr pixel_buf(new unsigned[len]); + //Find the char that should be splitted - graph.glyph_pixels(i.begin, len, pxbuf); + graph.glyph_pixels(i.begin, len, pixel_buf.get()); std::size_t idx_head = 0, idx_splitted; do { + auto pxbuf = pixel_buf.get(); + idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf); if(idx_splitted == len) { detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); + for(std::size_t i = idx_head; i < len; ++i) pos.x += static_cast(pxbuf[i]); + break; } //Check the word whether it is splittable. @@ -243,7 +254,7 @@ namespace nana detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); idx_head = idx_splitted; pos.x = x; - pos.y += line_pixels; + pos.y += static_cast(line_pixels); line_pixels = i_ts_keeper->height; } else @@ -283,18 +294,16 @@ namespace nana for(std::size_t k = idx_head; k < idx_head + splen; ++k) pos.x += static_cast(pxbuf[k]); + if (pos.x >= endpos) { pos.x = x; pos.y += static_cast(line_pixels); - line_pixels = i_ts_keeper->height; } idx_head += splen; } } }while(idx_head < len); - - delete [] pxbuf; } else { @@ -340,7 +349,7 @@ namespace nana { point pos{ endpos, top }; auto i_ts_keeper = ts_keeper.crbegin(); - for(auto i = reordered.crbegin(), end = reordered.crend(); i != end; ++i) + for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) { auto & ent = *i; std::size_t len = ent.end - ent.begin; @@ -397,9 +406,6 @@ namespace nana { graphics & graph; int x, endpos; - nana::unicode_bidi bidi; - std::vector reordered; - std::vector ts_keeper; unsigned extents; extent_auto_changing_lines(graphics& graph, int x, int endpos) @@ -412,8 +418,10 @@ namespace nana drawable_type dw = graph.handle(); unsigned str_w = 0; - ts_keeper.clear(); - bidi.linestr(buf, bufsize, reordered); + std::vector ts_keeper; + + auto const reordered = unicode_reorder(buf, bufsize); + for(auto & i : reordered) { nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); @@ -503,7 +511,6 @@ namespace nana { xpos = x; top += line_pixels; - line_pixels = i_ts_keeper->height; } idx_head += splen; } @@ -645,11 +652,9 @@ namespace nana substr_px += *p; } while (p != end); - pos.x += static_cast(width - ellipsis - substr_px); - - graph_.string(pos, "..."); - pos.x += ellipsis; + pos.x += static_cast(width - ellipsis - substr_px) + ellipsis; graph_.bidi_string(pos, text.c_str() + substr_len, text.size() - substr_len); + pos.x -= ellipsis; } else { @@ -669,8 +674,9 @@ namespace nana graph_.bidi_string(pos, text.c_str(), substr_len); pos.x += substr_px; - graph_.string(pos, "..."); } + + graph_.string(pos, "..."); } //end class string diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 3da7d2f0..15b77d12 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -276,8 +276,7 @@ namespace nana if(ch <= 0x1CC7) return L; //N = 141 if(0x1CD3 == ch || 0x1CE1 == ch) return L; if(ch <= 0x1CE8) return NSM; //N = 7 - if(0x1CED == ch) return NSM; - if(0x1CF4 == ch) return NSM; + if(0x1CED == ch || 0x1CF4 == ch) return NSM; if(ch <= 0x1DBF) return L; //N = 203 if(ch <= 0x1DFF) return NSM; //N = 64 if(ch <= 0x1FBC) return L; //N = 445 @@ -504,21 +503,21 @@ namespace nana } //class unicode_bidi - void unicode_bidi::linestr(const char_type* str, std::size_t len, std::vector & reordered) + std::vector unicode_bidi::reorder(const char_type* str, std::size_t len) { levels_.clear(); const char_type * const end = str + len; std::vector stack; - - remember cur = {0, directional_override_status::neutral}; + + remember cur = { 0, directional_override_status::neutral }; cur.level = _m_paragraph_level(str, end); //First character type bidi_char begin_char_type = {}; const char_type * begin_character = nullptr; - for(const char_type * c = str; c < end; ++c) + for (const char_type * c = str; c < end; ++c) { if (PDF == *c) { @@ -579,13 +578,17 @@ namespace nana begin_character = c; } } - if(begin_character) + if (begin_character) _m_push_entity(begin_character, end, cur.level, begin_char_type); _m_resolve_weak_types(); _m_resolve_neutral_types(); _m_resolve_implicit_levels(); + + std::vector reordered; _m_reordering_resolved_levels(reordered); + + return reordered; } unsigned unicode_bidi::_m_paragraph_level(const char_type * begin, const char_type * end) @@ -938,4 +941,9 @@ namespace nana return static_cast(static_cast(type - bidi_charmap::B) + 0x2000); } //end class unicode_bidi + + std::vector unicode_reorder(const wchar_t* text, std::size_t length) + { + return unicode_bidi{}.reorder(text, length); + } }//end namespace nana From a6c6a841476899f0bb9f7dc4a6abfc14d623b88c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 2 Jun 2017 04:26:19 +0800 Subject: [PATCH 15/28] fix crash that text_editor undo enter with selected text --- source/gui/widgets/skeletons/text_editor.cpp | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index f1076238..2891e655 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -143,6 +143,11 @@ namespace nana{ namespace widgets //sel_a_ and sel_b_ are not sorted, sel_b_ keeps the caret position. sel_a_ = editor_.select_.a; sel_b_ = editor_.select_.b; + + if (sel_a_ != sel_b_) + { + selected_text_ = editor_._m_make_select_string(); + } } void set_caret_pos() @@ -179,8 +184,7 @@ namespace nana{ namespace widgets void set_removed(std::wstring str) { - //use selected_text_ as removed text - selected_text_ = str; + selected_text_ = std::move(str); } void execute(bool redo) override @@ -287,15 +291,15 @@ namespace nana{ namespace widgets } else editor_.textbase().erase(pos_.y, pos_.x, text_.size()); //undo + } - if (!selected_text_.empty()) - { - editor_.points_.caret = sel_a_; - editor_._m_put(selected_text_); - editor_.points_.caret = sel_b_; - editor_.select_.a = sel_a_; //Reset the selected text - editor_.select_.b = sel_b_; - } + if (!selected_text_.empty()) + { + editor_.points_.caret = (std::min)(sel_a_, sel_b_); + editor_._m_put(selected_text_); + editor_.points_.caret = sel_b_; + editor_.select_.a = sel_a_; //Reset the selected text + editor_.select_.b = sel_b_; } } editor_.move_caret(editor_.points_.caret); @@ -2161,8 +2165,6 @@ namespace nana{ namespace widgets } else { - undo_ptr->set_removed(this->_m_make_select_string()); - undo_ptr->set_selected_text(); points_.caret = _m_erase_select(); undo_ptr->set_caret_pos(); From 4d93c97c44e1adfe8425e2b002123390c2aaf384 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 2 Jun 2017 05:19:38 +0800 Subject: [PATCH 16/28] small improvement --- source/gui/widgets/skeletons/text_editor.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 2891e655..3d5077bf 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1245,10 +1245,9 @@ namespace nana{ namespace widgets return false; _m_reset(); - impl_->capacities.behavior->pre_calc_lines(width_pixels()); impl_->try_refresh = sync_graph::refresh; - _m_reset_content_size(); + _m_reset_content_size(true); return true; } @@ -2104,26 +2103,22 @@ namespace nana{ namespace widgets void text_editor::del() { - bool has_erase = true; - if(select_.a == select_.b) { if(textbase().getline(points_.caret.y).size() > points_.caret.x) { ++points_.caret.x; } - else if(points_.caret.y + 1 < textbase().lines()) + else if (points_.caret.y + 1 < textbase().lines()) { //Move to next line points_.caret.x = 0; - ++ points_.caret.y; + ++points_.caret.y; } else - has_erase = false; //No characters behind the caret + return; //No characters behind the caret } - if(has_erase) backspace(); - - _m_reset_content_size(); + backspace(); } void text_editor::backspace(bool record_undo) @@ -2847,7 +2842,7 @@ namespace nana{ namespace widgets else { if (calc_lines) - impl_->capacities.behavior->pre_calc_lines(0); + impl_->capacities.behavior->pre_calc_lines(width_pixels()); auto maxline = textbase().max_line(); csize.width = _m_text_extent_size(textbase().getline(maxline.first).c_str(), maxline.second).width + caret_size().width; From d384a6a8e7629bbcdf19049b9b2411ac85ee23db Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 4 Jun 2017 05:47:57 +0800 Subject: [PATCH 17/28] fix issue that graphics::gradual_rectangle modifies fgcolor unexpectedly --- source/detail/mswin/platform_spec.hpp | 3 +-- source/detail/platform_spec_posix.cpp | 29 ------------------------- source/detail/platform_spec_windows.cpp | 5 ----- source/detail/posix/platform_spec.hpp | 3 +-- source/gui/widgets/listbox.cpp | 11 ---------- source/paint/graphics.cpp | 9 +++++--- 6 files changed, 8 insertions(+), 52 deletions(-) diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index 6de8c4e2..ed4b0d9a 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -144,7 +144,6 @@ namespace detail drawable_impl_type(); ~drawable_impl_type(); - void fgcolor(const ::nana::color&); //deprecated unsigned get_color() const; unsigned get_text_color() const; void set_color(const ::nana::color&); diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 89ea7b8c..0b7e9538 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -423,35 +423,6 @@ namespace detail } } - void drawable_impl_type::fgcolor(const ::nana::color& clr) - { - auto rgb = clr.px_color().value; - - if (rgb != current_color_) - { - auto & spec = nana::detail::platform_spec::instance(); - platform_scope_guard psg; - - current_color_ = rgb; - switch(spec.screen_depth()) - { - case 16: - rgb = ((((rgb >> 16) & 0xFF) * 31 / 255) << 11) | - ((((rgb >> 8) & 0xFF) * 63 / 255) << 5) | - (rgb & 0xFF) * 31 / 255; - break; - } - ::XSetForeground(spec.open_display(), context, rgb); - ::XSetBackground(spec.open_display(), context, rgb); -#if defined(NANA_USE_XFT) - xft_fgcolor.color.red = ((0xFF0000 & rgb) >> 16) * 0x101; - xft_fgcolor.color.green = ((0xFF00 & rgb) >> 8) * 0x101; - xft_fgcolor.color.blue = (0xFF & rgb) * 0x101; - xft_fgcolor.color.alpha = 0xFFFF; -#endif - } - } - platform_scope_guard::platform_scope_guard() { platform_spec::instance().lock_xlib(); diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index 3e4e044b..eb58c603 100644 --- a/source/detail/platform_spec_windows.cpp +++ b/source/detail/platform_spec_windows.cpp @@ -221,11 +221,6 @@ namespace detail ::DeleteObject(round_region.handle); } - void drawable_impl_type::fgcolor(const ::nana::color& clr) - { - set_text_color(clr); - } - unsigned drawable_impl_type::get_color() const { return color_; diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index f1f32448..2ada1eac 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -101,7 +101,6 @@ namespace detail drawable_impl_type(); ~drawable_impl_type(); - void fgcolor(const ::nana::color&); //deprecated unsigned get_color() const; unsigned get_text_color() const; void set_color(const ::nana::color&); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 1b33d880..3aa2262f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2248,7 +2248,6 @@ namespace nana if (seq.empty()) return 0; - //return (header.position(seq[0], nullptr) - this->content_view->origin().x + r.x); //deprecated return header.range(seq.front()).first + r.x - this->content_view->origin().x; } @@ -3226,14 +3225,10 @@ namespace nana auto i = essence_->header.column_from_point(x); if (i == npos) - //i = essence_->header.boundary(essence_->header.position(grab, nullptr) >= x); //deprecated i = essence_->header.boundary(essence_->header.range(grab).first >= x); if(grab != i) { - //unsigned item_pixels = 0; - //auto item_x = essence_->header.position(i, &item_pixels); //deprecated - auto item_rg = essence_->header.range(i); //Get the item pos @@ -3319,7 +3314,6 @@ namespace nana _m_draw_header_item(fl_graph, margin, rectangle{ fl_graph.size()}, colors::white, col, item_state::floated); - //auto xpos = essence_->header.position(col.index, nullptr) + pos.x - grabs_.start_pos; //deprecated auto xpos = essence_->header.range(col.index).first + pos.x - grabs_.start_pos; essence_->graph->blend(rectangle{ point{ xpos - essence_->content_view->origin().x + rect.x, rect.y } , fl_graph.size() }, fl_graph, {}, 0.5); } @@ -3405,7 +3399,6 @@ namespace nana auto & ptr_where = essence_->pointer_where; - //int item_top = rect.y - (origin.y % item_height_px); //deprecated auto first_disp = essence_->first_display(); point item_coord{ @@ -3444,8 +3437,6 @@ namespace nana ind->detach(); } - //const int x = essence_->item_xpos(rect); //deprecated - //Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos)) if (idx.cat == 0 || !idx.is_category()) { @@ -3579,7 +3570,6 @@ namespace nana //Draw selecting inner rectangle if (item.flags.selected && (categ.expand == false)) - //_m_draw_item_border(r.x, y, (std::min)(r.width, width - essence_->content_view->origin().x)); //deprecated _m_draw_item_border(y); } @@ -3816,7 +3806,6 @@ namespace nana //Draw selecting inner rectangle if (item.flags.selected) - //_m_draw_item_border(content_r.x, coord.y, show_w); //deprecated _m_draw_item_border(coord.y); } diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index b3bedd40..18a9df2a 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -1208,7 +1208,8 @@ namespace paint unsigned last_color = (int(r) << 16) | (int(g) << 8) | int(b); Display * disp = nana::detail::platform_spec::instance().open_display(); - impl_->handle->fgcolor(static_cast(last_color)); + impl_->handle->set_color(static_cast(last_color)); + impl_->handle->update_color(); const int endpos = deltapx + (vertical ? rct.y : rct.x); if (endpos > 0) { @@ -1223,7 +1224,8 @@ namespace paint if (new_color != last_color) { last_color = new_color; - impl_->handle->fgcolor(static_cast(last_color)); + impl_->handle->set_color(static_cast(last_color)); + impl_->handle->update_color(); } } } @@ -1238,7 +1240,8 @@ namespace paint if (new_color != last_color) { last_color = new_color; - impl_->handle->fgcolor(static_cast(last_color)); + impl_->handle->set_color(static_cast(last_color)); + impl_->handle->update_color(); } } } From bd38e96ed78e9600b9fdee178e68755ffba25edd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 8 Jun 2017 00:44:27 +0800 Subject: [PATCH 18/28] fix issue that textbox&spinbox don't update immediately --- source/gui/widgets/spinbox.cpp | 6 +++++- source/gui/widgets/textbox.cpp | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 87cec724..2cb89870 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -441,7 +441,10 @@ namespace nana text = to_wstring(modifier_.prefix + range_->value() + modifier_.suffix); if (editor_->text() != text) + { editor_->text(text, false); + editor_->try_refresh(); + } _m_draw_spins(spin_stated_); } @@ -736,7 +739,8 @@ namespace nana if (editor) { editor->text(to_wstring(text), false); - API::refresh_window(*this); + if (editor->try_refresh()) + API::update_window(*this); } } }//end namespace nana diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 909cde92..5ae9454b 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -738,7 +738,9 @@ namespace drawerbase { if (editor) { editor->text(to_wstring(str), false); - API::update_window(this->handle()); + + if (editor->try_refresh()) + API::update_window(this->handle()); } } From 93514186d5ea2098f859d3c11d567e6b104a00e8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 8 Jun 2017 21:45:00 +0800 Subject: [PATCH 19/28] fix some typo --- source/gui/place.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index c0a4f972..f1b4a5ff 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -3055,7 +3055,7 @@ namespace nana void place::bind(window wd) { if (impl_->window_handle) - throw std::runtime_error("place.bind: it has already binded to a window."); + throw std::runtime_error("place.bind: it has already bound to a window."); impl_->window_handle = wd; impl_->event_size_handle = API::events(wd).resized.connect([this](const arg_resized& arg) From 0b4dc1904b8dcf6cf8433bbfb2d6caba2c46dbce Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 11 Jun 2017 11:33:52 +0800 Subject: [PATCH 20/28] fix compiler errors/warnings for clang 5.0 --- include/nana/c++defines.hpp | 2 +- include/nana/gui/detail/basic_window.hpp | 2 +- include/nana/gui/widgets/listbox.hpp | 8 ++++---- include/nana/gui/widgets/menubar.hpp | 1 - source/audio/detail/buffer_preparation.cpp | 2 +- source/charset.cpp | 10 ++++++++-- source/detail/platform_spec_posix.cpp | 2 +- source/gui/animation.cpp | 2 +- source/gui/filebox.cpp | 2 +- source/gui/notifier.cpp | 3 +++ source/gui/place_parts.hpp | 4 ++-- source/gui/widgets/listbox.cpp | 4 ++-- source/gui/widgets/menubar.cpp | 2 +- source/gui/widgets/skeletons/text_editor.cpp | 2 +- source/gui/widgets/treebox.cpp | 2 +- source/paint/truetype.hpp | 2 +- 16 files changed, 29 insertions(+), 21 deletions(-) diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp index 551b45bb..a9381f23 100644 --- a/include/nana/c++defines.hpp +++ b/include/nana/c++defines.hpp @@ -62,7 +62,7 @@ # else # undef STD_FILESYSTEM_NOT_SUPPORTED # endif -#elif defined(__GNUC__) +#elif defined(__GNUC__) && not defined(__clang__) # if (__GNUC__ == 4 && __GNUC_MINOR__ < 6) # define noexcept //no support of noexcept until GCC 4.6 # endif diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 2230a422..c686f889 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -52,7 +52,7 @@ namespace detail void position(const point& pos) override; nana::point position() const override; size dimension() const override; - void dimension(const size& s); + void dimension(const size& s) override; void visible(bool visibility) override; bool visible() const override; private: diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 552b2e36..e7ac1601 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -419,7 +419,7 @@ namespace nana throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } - void erase(std::size_t pos) override + void erase(std::size_t /*pos*/) override { throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } @@ -434,7 +434,7 @@ namespace nana return true; } - void emplace(std::size_t pos) override + void emplace(std::size_t /*pos*/) override { throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } @@ -444,7 +444,7 @@ namespace nana throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } - void assign(std::size_t pos, const std::vector& cells) override + void assign(std::size_t /*pos*/, const std::vector& /*cells*/) override { throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } @@ -454,7 +454,7 @@ namespace nana return ctrans_(container_.at(pos)); } - bool push_back(const const_virtual_pointer& dptr) override + bool push_back(const const_virtual_pointer& /*dptr*/) override { throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); } diff --git a/include/nana/gui/widgets/menubar.hpp b/include/nana/gui/widgets/menubar.hpp index b636a125..a76b21bb 100644 --- a/include/nana/gui/widgets/menubar.hpp +++ b/include/nana/gui/widgets/menubar.hpp @@ -50,7 +50,6 @@ namespace nana virtual void caption(const point&, const native_string_type&); scheme *scheme_ptr() const { return scheme_ptr_; }; private: - window handle_; graph_reference graph_; scheme *scheme_ptr_; }; diff --git a/source/audio/detail/buffer_preparation.cpp b/source/audio/detail/buffer_preparation.cpp index acd0aaa3..82942846 100644 --- a/source/audio/detail/buffer_preparation.cpp +++ b/source/audio/detail/buffer_preparation.cpp @@ -33,7 +33,7 @@ namespace nana{ namespace audio prepared_.emplace_back(m); } - thr_ = std::move(std::thread([this](){this->_m_prepare_routine();})); + thr_ = std::thread{[this](){this->_m_prepare_routine();}}; } buffer_preparation::~buffer_preparation() diff --git a/source/charset.cpp b/source/charset.cpp index 5c802b15..454b5ea3 100644 --- a/source/charset.cpp +++ b/source/charset.cpp @@ -484,7 +484,7 @@ namespace nana virtual std::string&& str_move() { if(is_unicode_) - data_ = std::move(str()); + data_ = str(); return std::move(data_); } @@ -506,6 +506,8 @@ namespace nana std::u32string u32str = std::wstring_convert, char32_t>().from_bytes(data_); return std::string(reinterpret_cast(u32str.c_str()), u32str.size() * sizeof(char32_t)); } + default: + break; //no conversion } break; case unicode::utf16: @@ -520,6 +522,8 @@ namespace nana std::u32string u32str = std::wstring_convert, char32_t>().from_bytes(data_); return std::string(reinterpret_cast(u32str.c_str()), u32str.size() * sizeof(char32_t)); } + default: + break; //no conversion } break; case unicode::utf32: @@ -533,6 +537,8 @@ namespace nana return std::wstring_convert, char32_t>().to_bytes( std::u32string(reinterpret_cast(data_.c_str()), data_.size() / sizeof(char32_t)) ); + default: + break; //no conversion } break; } @@ -588,7 +594,7 @@ namespace nana virtual std::wstring && wstr_move() { - wdata_for_move_ = std::move(wstr()); + wdata_for_move_ = wstr(); return std::move(wdata_for_move_); } private: diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 0b7e9538..e495cf7d 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/source/gui/animation.cpp b/source/gui/animation.cpp index a6047b4e..c737d334 100644 --- a/source/gui/animation.cpp +++ b/source/gui/animation.cpp @@ -454,7 +454,7 @@ namespace nana thr->performance_parameter = 0.0; thr->fps = p->fps; thr->interval = 1000.0 / double(p->fps); - thr->thread = std::make_shared([this, thr]() + thr->thread = std::make_shared([thr]() { nana::system::timepiece tmpiece; while (true) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index ae90915d..c3fa7fb0 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -270,7 +270,7 @@ namespace nana return (reverse ? a > b : a < b); }); - ls_file_.set_sort_compare(3, [this](const std::string&, nana::any* anyptr_a, const std::string&, nana::any* anyptr_b, bool reverse) -> bool + ls_file_.set_sort_compare(3, [](const std::string&, nana::any* anyptr_a, const std::string&, nana::any* anyptr_b, bool reverse) -> bool { item_fs * fsa = any_cast(anyptr_a); item_fs * fsb = any_cast(anyptr_b); diff --git a/source/gui/notifier.cpp b/source/gui/notifier.cpp index 545b3a47..e3ec1b66 100644 --- a/source/gui/notifier.cpp +++ b/source/gui/notifier.cpp @@ -265,6 +265,9 @@ namespace nana auto ico = impl_->icons[impl_->play_index++]; impl_->set_icon(ico); +#else + //eliminates warnings in clang + static_cast(this); #endif }); diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 0b4f4e23..3dde6ca9 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -68,13 +68,13 @@ namespace nana API::dev::lazy_refresh(); } - void mouse_down(graph_reference graph, const arg_mouse&) + void mouse_down(graph_reference graph, const arg_mouse&) override { refresh(graph); API::dev::lazy_refresh(); } - void mouse_up(graph_reference graph, const arg_mouse&) + void mouse_up(graph_reference graph, const arg_mouse&) override { refresh(graph); API::dev::lazy_refresh(); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3aa2262f..237212c4 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -195,7 +195,7 @@ namespace nana _m_refresh(); } - void width(unsigned minimum, unsigned maximum) + void width(unsigned minimum, unsigned maximum) override { //maximum must be larger than minimum, but maximum == 0 is allowed if minimum is 0 if ((minimum >= maximum) && (minimum != 0)) @@ -3531,7 +3531,7 @@ namespace nana } } private: - void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, nana::color bgcolor, item_state state) + void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, const nana::rectangle& /*r*/, nana::color bgcolor, item_state state) { const auto item_height = essence_->item_height(); diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 9b17d1e7..8ad5e35b 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -85,7 +85,7 @@ namespace nana //class item_renderer item_renderer::item_renderer(window wd, graph_reference graph) - :handle_(wd), graph_(graph), scheme_ptr_(static_cast(API::dev::get_scheme(wd))) + :graph_(graph), scheme_ptr_(static_cast(API::dev::get_scheme(wd))) {} void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index d008d70a..11061b58 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -440,7 +440,7 @@ namespace nana{ namespace widgets ); } - bool clear() + bool clear() override { if (colored_areas_.empty()) return false; diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 54c94f94..c84e66d2 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -2200,7 +2200,7 @@ namespace nana } path.insert(0, pnode->value.first); - return std::move(path); + return path; } return{}; } diff --git a/source/paint/truetype.hpp b/source/paint/truetype.hpp index bd44c0db..5b94cd34 100644 --- a/source/paint/truetype.hpp +++ b/source/paint/truetype.hpp @@ -66,7 +66,7 @@ namespace nana if (ifs.read(reinterpret_cast(&table_directory), sizeof table_directory).gcount() != sizeof table_directory) return; - if (reinterpret_cast("name") == reinterpret_cast(table_directory.name)) + if (*reinterpret_cast("name") == reinterpret_cast(table_directory.name)) { //const std::size_t length = _m_swap(table_directory.length); const std::size_t directory_offset = _m_swap(table_directory.offset); From 40cfe5f404faf1a26693636ec1d38278585d2198 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 13 Jun 2017 06:00:30 +0800 Subject: [PATCH 21/28] fix bug that listbox would crash when selects category by box selection --- source/gui/widgets/listbox.cpp | 101 +++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index cc32afac..94a73ec3 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1507,14 +1507,38 @@ namespace nana } template - std::vector> select_display_range_if(index_pair fr_abs, index_pair to_dpl, bool unselect_others, Pred pred) + std::vector> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool unselect_others, Pred pred) { const auto already_selected = this->pick_items(true); - auto fr_dpl = this->index_cast(fr_abs, false); //Converts an absolute position to display position + auto fr_dpl = (fr_abs.is_category() ? fr_abs : this->index_cast(fr_abs, false)); //Converts an absolute position to display position if (fr_dpl > to_dpl) std::swap(fr_dpl, to_dpl); + if (to_dpl.is_category()) + { + auto size = this->size_item(to_dpl.cat); + if (0 == size) + { + while (to_dpl.cat > 0) + { + size = this->size_item(--to_dpl.cat); + if (size > 0) + { + to_dpl.item = size - 1; + break; + } + } + } + else if (size > 0) + { + to_dpl.item = size - 1; + } + } + + if (!this->good(to_dpl)) + to_dpl = this->last(); + const auto begin = fr_dpl; const auto last = to_dpl; @@ -1524,7 +1548,26 @@ namespace nana for (; fr_dpl != to_dpl; fr_dpl = advance(fr_dpl, 1)) { - if (!fr_dpl.is_category()) + if (fr_dpl.is_category()) + { + if (!expand(fr_dpl.cat)) + { + auto size = size_item(fr_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); + } + + if (fr_dpl.cat == to_dpl.cat) + break; + } + } + else { auto abs_pos = index_cast(fr_dpl, true); //convert display position to absolute position item_proxy m{ ess_, abs_pos }; @@ -1535,7 +1578,23 @@ namespace nana } } - if (!to_dpl.is_category()) + 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 @@ -2088,18 +2147,21 @@ namespace nana return; } - auto begin_off = (std::max)((std::min)(mouse_selection.begin_position.y, mouse_selection.end_position.y), 0) / item_height(); - auto last_off = (std::max)(mouse_selection.begin_position.y, mouse_selection.end_position.y) / item_height(); + auto const begin_off = (std::max)((std::min)(mouse_selection.begin_position.y, mouse_selection.end_position.y), 0) / item_height(); auto begin = lister.advance(lister.first(), begin_off); - auto last = lister.advance(lister.first(), last_off); + if (begin.empty()) + return; - if (!lister.good(last)) - last = lister.last(); + std::vector> selections; - if (lister.good(begin) && ((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)) { - auto selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) { + //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 = lister.advance(lister.first(), last_off); + + selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) { if (this->mouse_selection.reverse_selection) { if(mouse_selection.already_selected.cend() != std::find(mouse_selection.already_selected.cbegin(), mouse_selection.already_selected.cend(), abs_pos)) @@ -2139,16 +2201,6 @@ namespace nana ++i; } - if (mouse_selection.reverse_selection) - { - for (auto & abs_pos : mouse_selection.already_selected) - { - if (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), pred_mouse_selection{abs_pos})) - { - item_proxy{ this, abs_pos }.select(true); - } - } - } } else { @@ -2158,10 +2210,13 @@ namespace nana } mouse_selection.selections.clear(); + } - if (mouse_selection.reverse_selection) + if (mouse_selection.reverse_selection) + { + for (auto & abs_pos : mouse_selection.already_selected) { - for (auto & abs_pos : mouse_selection.already_selected) + if (selections.empty() || (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), pred_mouse_selection{ abs_pos }))) { item_proxy{ this, abs_pos }.select(true); } From 8044cb0b343727a8ff6a271ebde024b03f7d83bd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 13 Jun 2017 23:25:58 +0800 Subject: [PATCH 22/28] fix some bugs of listbox box selection --- source/gui/widgets/listbox.cpp | 218 ++++++++++++++++----------------- 1 file changed, 104 insertions(+), 114 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 94a73ec3..c5d7aa46 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1517,22 +1517,20 @@ namespace nana if (to_dpl.is_category()) { - auto size = this->size_item(to_dpl.cat); - if (0 == size) + //Search backward until a last item of a category is found. + 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); - if (size > 0) - { - to_dpl.item = size - 1; - break; - } + to_dpl.item = msize - 1; + break; } - } - else if (size > 0) - { - to_dpl.item = size - 1; + + if (fr_dpl.cat == to_dpl.cat) + break; + + --(to_dpl.cat); } } @@ -1546,7 +1544,7 @@ namespace nana //pair second: indicates whether the index is selected before selection. std::vector> 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()) { @@ -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) { //Unselects the already selected which is out of range [begin, last] @@ -1638,9 +1609,9 @@ namespace nana this->emit_cs(pos, true); if (m.flags.selected) - last_selected_abs = pos; - else if (last_selected_abs == pos) - last_selected_abs.set_both(npos); //make empty + latest_selected_abs = pos; + else if (latest_selected_abs == pos) + latest_selected_abs.set_both(npos); //make empty } } ++pos.item; @@ -1879,8 +1850,13 @@ namespace nana else i.item = npos; } - else if (i.item) - --i.item; + else + { + if (i.item) + --i.item; + else + return index_pair{ npos, npos }; + } 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 index_pair first() const noexcept { - index_pair fst{0,npos}; - good_item(fst,fst); - return fst; + auto i = categories_.cbegin(); + if (i->items.size()) + 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 @@ -1903,36 +1884,6 @@ namespace nana 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 container::iterator get(size_type pos) { @@ -1952,7 +1903,7 @@ namespace nana return i; } 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: essence * ess_{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 { - 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 { @@ -3053,8 +3004,8 @@ namespace nana for (item_proxy &it : cpx) it.select(value); - last_selected_abs.cat = pos; - last_selected_abs.item = npos; + latest_selected_abs.cat = pos; + latest_selected_abs.item = npos; return true; } @@ -4124,18 +4075,18 @@ namespace nana if (arg.shift) { //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); + //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); - 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; }); - lister.last_selected_abs = before; + lister.latest_selected_abs = before; } else if (arg.ctrl) { @@ -4176,10 +4127,10 @@ namespace nana if (item_ptr->flags.selected) { 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) - essence_->lister.last_selected_abs.set_both(npos); + else if (essence_->lister.latest_selected_abs == abs_item_pos) + essence_->lister.latest_selected_abs.set_both(npos); } } else @@ -4350,17 +4301,18 @@ namespace nana void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { - bool up = false; + // Exit if list is empty + if (essence_->lister.first().empty()) + return; - if (essence_->lister.cat_container().size() == 1 && essence_->lister.size_item(0)==0) - return ; + bool upward = false; switch(arg.key) { case keyboard::os_arrow_up: - up = true; + upward = true; case keyboard::os_arrow_down: - essence_->lister.move_select(up, !arg.shift, true); + essence_->lister.move_select(upward, !arg.shift, true); break; case L' ': { @@ -4371,18 +4323,18 @@ namespace nana } break; case keyboard::os_pageup : - up = true; + upward = true; case keyboard::os_pagedown: { //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; essence_->lister.select_for_all(false); auto idx = essence_->first_display(); - if (!up) + if (!upward) idx = essence_->lister.advance(idx, static_cast(essence_->count_of_exposed(false)) - 1); if (!idx.is_category()) @@ -4393,20 +4345,59 @@ namespace nana break; } case keyboard::os_home: + case keyboard::os_end: { essence_->lister.select_for_all(false); - index_pair frst{essence_->lister.first()}; - if (! frst.is_category()) - item_proxy::from_display(essence_, frst).select(true); - else if (!essence_->lister.single_status(true)) //not selected - essence_->lister.cat_status(frst.cat, true, true); + auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.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. + //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; + } + } + } + else + { + while (0 == essence_->lister.size_item(pos.cat)) + { + if (pos.cat-- == 0) + { + pos = index_pair{ npos, npos }; + break; + } + } + } - 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); + } + } } - case keyboard::os_end: - essence_->lister.select_for_all(false); - item_proxy::from_display(essence_, essence_->lister.last()).select(true); break; default: return; @@ -4531,10 +4522,10 @@ namespace nana 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.last_selected_abs = pos_; + ess_->lister.latest_selected_abs = pos_; } - else if (ess_->lister.last_selected_abs == pos_) - ess_->lister.last_selected_abs.set_both(npos); + else if (ess_->lister.latest_selected_abs == pos_) + ess_->lister.latest_selected_abs.set_both(npos); if (scroll_view) { @@ -4808,7 +4799,7 @@ namespace nana for (item_proxy &it : *this ) 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; } @@ -5432,7 +5423,6 @@ namespace nana { auto & ess = _m_ess(); ess.lister.erase(); - //ess.first_display(ess.lister.first()); ess.calc_content_size(); ess.update(); } From 33321d73dec5555f21ea6690a687077645f73c64 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 17 Jun 2017 10:48:24 +0800 Subject: [PATCH 23/28] fix logic and crash errors of listbox box selection --- source/gui/widgets/listbox.cpp | 224 +++++++++++++++------------------ 1 file changed, 100 insertions(+), 124 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index c5d7aa46..9ac67c5c 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1507,36 +1507,22 @@ namespace nana } template - std::vector> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool unselect_others, Pred pred) + std::vector> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool deselect_others, Pred pred) { - const auto already_selected = this->pick_items(true); + const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{}); + + if (to_dpl.empty()) + { + if (fr_abs.empty()) + return{}; + + to_dpl = this->last(); + } auto fr_dpl = (fr_abs.is_category() ? fr_abs : this->index_cast(fr_abs, false)); //Converts an absolute position to display position if (fr_dpl > to_dpl) std::swap(fr_dpl, to_dpl); - if (to_dpl.is_category()) - { - //Search backward until a last item of a category is found. - while (true) - { - auto msize = this->size_item(to_dpl.cat); - if (0 != msize) - { - to_dpl.item = msize - 1; - break; - } - - if (fr_dpl.cat == to_dpl.cat) - break; - - --(to_dpl.cat); - } - } - - if (!this->good(to_dpl)) - to_dpl = this->last(); - const auto begin = fr_dpl; const auto last = to_dpl; @@ -1576,9 +1562,9 @@ namespace nana } } - if (unselect_others) + if (deselect_others) { - //Unselects the already selected which is out of range [begin, last] + //Deselects the already selected which is out of range [begin, last] for (auto index : already_selected) { auto disp_order = this->index_cast(index, false); //converts an absolute position to a display position @@ -1935,6 +1921,7 @@ namespace nana bool auto_draw{true}; bool checkable{false}; bool if_image{false}; + bool deselect_deferred{ false }; //deselects items when mouse button is released. unsigned text_height; ::nana::listbox::export_options def_exp_options; @@ -2059,16 +2046,19 @@ namespace nana return{ r.x - origin.x, r.x - origin.x + static_cast(header.pixels()) }; } - void start_mouse_selection(const point& screen_pos) + void start_mouse_selection(const arg_mouse& arg) { - auto logic_pos = coordinate_cast(screen_pos, true); + auto logic_pos = coordinate_cast(arg.pos, true); mouse_selection.started = true; mouse_selection.begin_position = logic_pos; mouse_selection.end_position = logic_pos; - mouse_selection.already_selected = lister.pick_items(true); - + if (arg.ctrl || arg.shift) + { + mouse_selection.already_selected = lister.pick_items(true); + mouse_selection.reverse_selection = arg.ctrl; + } API::set_capture(*listbox_ptr, true); } @@ -2089,90 +2079,89 @@ namespace nana mouse_selection.end_position = logic_pos; + bool cancel_selections = true; + 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 || - (std::min)(mouse_selection.end_position.x, mouse_selection.begin_position.x) >= content_x + static_cast(header.pixels()) - ) + if ((std::max)(mouse_selection.end_position.x, mouse_selection.begin_position.x) >= content_x && + (std::min)(mouse_selection.end_position.x, mouse_selection.begin_position.x) < content_x + static_cast(header.pixels())) { - lister.select_for_all(false); - return; - } + auto const begin_off = (std::max)((std::min)(mouse_selection.begin_position.y, mouse_selection.end_position.y), 0) / item_height(); - auto const begin_off = (std::max)((std::min)(mouse_selection.begin_position.y, mouse_selection.end_position.y), 0) / item_height(); - - auto begin = lister.advance(lister.first(), begin_off); - if (begin.empty()) - return; - - std::vector> selections; - - 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 - 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); - - selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) { - if (this->mouse_selection.reverse_selection) - { - if(mouse_selection.already_selected.cend() != std::find(mouse_selection.already_selected.cbegin(), mouse_selection.already_selected.cend(), abs_pos)) - { - item_proxy{ this, abs_pos }.select(false); - return false; - } - } - return true; - }); - - for (auto & pair : selections) + auto begin = lister.advance(lister.first(), begin_off); + if (!begin.empty()) { - if (pair.second) - continue; + std::vector> selections; - if (mouse_selection.selections.cend() == - std::find(mouse_selection.selections.cbegin(), mouse_selection.selections.cend(), pair.first)) + if ((mouse_selection.end_position.y < 0) || (lister.distance(lister.first(), begin) == begin_off)) { - mouse_selection.selections.push_back(pair.first); - } - } + //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 = lister.advance(lister.first(), last_off); + + selections = lister.select_display_range_if(begin, last, false, [this](const index_pair& abs_pos) { + if (this->mouse_selection.reverse_selection) + { + if (mouse_selection.already_selected.cend() != std::find(mouse_selection.already_selected.cbegin(), mouse_selection.already_selected.cend(), abs_pos)) + { + item_proxy{ this, abs_pos }.select(false); + return false; + } + } + return true; + }); + + for (auto & pair : selections) + { + if (pair.second) + continue; + + if (mouse_selection.selections.cend() == + std::find(mouse_selection.selections.cbegin(), mouse_selection.selections.cend(), pair.first)) + { + mouse_selection.selections.push_back(pair.first); + } + } #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 - 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 - { - if (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), pred_mouse_selection{*i})) - { - item_proxy{ this, *i }.select(false); - i = mouse_selection.selections.erase(i); - } - else - ++i; - } + { + if (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), pred_mouse_selection{ *i })) + { + item_proxy{ this, *i }.select(false); + i = mouse_selection.selections.erase(i); + } + else + ++i; + } - } - else - { - for (auto & pos : mouse_selection.selections) - { - item_proxy{ this, pos }.select(false); + cancel_selections = false; + } } + } + + if (cancel_selections) + { + if (!mouse_selection.already_selected.empty()) + { + for (auto & pos : mouse_selection.selections) + item_proxy(this, pos).select(false); + + //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) + item_proxy(this, abs_pos).select(true); + } + } + else + lister.select_for_all(false); mouse_selection.selections.clear(); } - - if (mouse_selection.reverse_selection) - { - for (auto & abs_pos : mouse_selection.already_selected) - { - if (selections.empty() || (selections.cend() == std::find_if(selections.cbegin(), selections.cend(), pred_mouse_selection{ abs_pos }))) - { - item_proxy{ this, abs_pos }.select(true); - } - } - } } void stop_mouse_selection() noexcept @@ -3934,6 +3923,9 @@ namespace nana using item_state = essence::item_state; using parts = essence::parts; + //Cancel deferred deselection operation when mouse moves. + essence_->deselect_deferred = false; + bool need_refresh = false; point pos_in_header = arg.pos; @@ -4153,23 +4145,6 @@ namespace nana } update = true; } - else - { - //Blank area is clicked - - bool unselect_all = true; - if (!lister.single_status(true)) //not single selected - { - if (arg.ctrl || arg.shift) - { - essence_->mouse_selection.reverse_selection = arg.ctrl; - unselect_all = false; - } - } - - if(unselect_all) - update = lister.select_for_all(false); //unselect all items due to the blank area being clicked - } if(update) { @@ -4187,16 +4162,11 @@ namespace nana { //Start box selection if mulit-selection is enabled if (arg.is_left_button() && (!lister.single_status(true))) - essence_->start_mouse_selection(arg.pos); + essence_->start_mouse_selection(arg); - lister.select_for_all(false); - update = true; - if (good_list_r) - { - drawer_lister_->draw(list_r); - if (good_head_r) - drawer_header_->draw(graph, head_r); - } + //Deselection of 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. + essence_->deselect_deferred = !(arg.ctrl || arg.shift); } if(update) @@ -4236,6 +4206,12 @@ namespace nana need_refresh = true; } + if (essence_->deselect_deferred) + { + essence_->deselect_deferred = false; + need_refresh |= (essence_->lister.select_for_all(false)); + } + if (need_refresh) { refresh(graph); From b5db21567fa23ae7afbbbad44fec4d8293bf66ca Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 18 Jun 2017 05:08:51 +0800 Subject: [PATCH 24/28] add new methods to textbox for line count --- .../gui/widgets/skeletons/text_editor.hpp | 2 ++ include/nana/gui/widgets/textbox.hpp | 11 ++++++++++ source/gui/widgets/skeletons/text_editor.cpp | 8 ++++++++ source/gui/widgets/textbox.cpp | 20 +++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/include/nana/gui/widgets/skeletons/text_editor.hpp b/include/nana/gui/widgets/skeletons/text_editor.hpp index 49bb0867..cf8ee302 100644 --- a/include/nana/gui/widgets/skeletons/text_editor.hpp +++ b/include/nana/gui/widgets/skeletons/text_editor.hpp @@ -183,6 +183,8 @@ namespace nana{ namespace widgets void focus_behavior(text_focus_behavior); void select_behavior(bool move_to_end); + + std::size_t line_count(bool text_lines) const; public: void draw_corner(); void render(bool focused); diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index e37ed6fc..6df66d18 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -257,6 +257,17 @@ namespace nana * @param len The length of the queue. If this parameter is zero, the undo/redo is disabled. */ void set_undo_queue_length(std::size_t len); + + /// Returns the number of lines that text are displayed in the screen. + /** + * The number of display lines may be not equal to the number of text lines when the textbox + * is line wrapped mode. + * @return the number of lines that text are displayed in the screen. + */ + std::size_t display_line_count() const; + + /// Returns the number of text lines. + std::size_t text_line_count() const; protected: //Overrides widget's virtual functions native_string_type _m_caption() const throw() override; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 3d5077bf..50d67b85 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1872,6 +1872,14 @@ namespace nana{ namespace widgets select_.move_to_end = move_to_end; } + std::size_t text_editor::line_count(bool text_lines) const + { + if (text_lines) + return textbase().lines(); + + return impl_->capacities.behavior->take_lines(); + } + void text_editor::draw_corner() { impl_->cview->draw_corner(graph_); diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index 5ae9454b..f0b3351c 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -720,6 +720,26 @@ namespace drawerbase { editor->set_undo_queue_length(len); } + std::size_t textbox::display_line_count() const + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + return editor->line_count(false); + + return 0; + } + + std::size_t textbox::text_line_count() const + { + internal_scope_guard lock; + auto editor = get_drawer_trigger().editor(); + if (editor) + return editor->line_count(true); + + return 0; + } + //Override _m_caption for caption() auto textbox::_m_caption() const throw() -> native_string_type { From 74dedb9506c67f640e832907ed4f4196504560f9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 18 Jun 2017 10:10:30 +0800 Subject: [PATCH 25/28] add noexcept --- include/nana/gui/widgets/textbox.hpp | 4 ++-- source/gui/widgets/textbox.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index 6df66d18..591b4e7e 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -264,10 +264,10 @@ namespace nana * is line wrapped mode. * @return the number of lines that text are displayed in the screen. */ - std::size_t display_line_count() const; + std::size_t display_line_count() const noexcept; /// Returns the number of text lines. - std::size_t text_line_count() const; + std::size_t text_line_count() const noexcept; protected: //Overrides widget's virtual functions native_string_type _m_caption() const throw() override; diff --git a/source/gui/widgets/textbox.cpp b/source/gui/widgets/textbox.cpp index f0b3351c..1be973ea 100644 --- a/source/gui/widgets/textbox.cpp +++ b/source/gui/widgets/textbox.cpp @@ -720,7 +720,7 @@ namespace drawerbase { editor->set_undo_queue_length(len); } - std::size_t textbox::display_line_count() const + std::size_t textbox::display_line_count() const noexcept { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); @@ -730,7 +730,7 @@ namespace drawerbase { return 0; } - std::size_t textbox::text_line_count() const + std::size_t textbox::text_line_count() const noexcept { internal_scope_guard lock; auto editor = get_drawer_trigger().editor(); From ad55c51a3e304a626ee0c0b35495c1840d662e22 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 21 Jun 2017 22:42:22 +0800 Subject: [PATCH 26/28] small fixes --- build/makefile/makefile | 1 - include/nana/gui/widgets/listbox.hpp | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build/makefile/makefile b/build/makefile/makefile index 9f0fb052..0cdc8d1d 100644 --- a/build/makefile/makefile +++ b/build/makefile/makefile @@ -8,7 +8,6 @@ SRCROOT = ../../source EXTRLIB = ../../extrlib NANA_INC= $(INCROOT)/nana OUTROOT = out -#CXXFLAGS= -g -std=c++11 -Wall CXXFLAGS= -g -fexceptions -std=c++11 -Wall -Wextra -Wunused-variable -Wfatal-errors INCS = -I$(INCROOT) -I/usr/include/freetype2 -I$(EXTRLIB) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 552b2e36..b6417524 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -186,7 +186,7 @@ namespace nana public: virtual ~container_interface() = default; - virtual void clear() noexcept = 0; + virtual void clear() = 0; virtual void erase(std::size_t pos) = 0; virtual std::size_t size() const = 0; @@ -238,7 +238,7 @@ namespace nana translator_({ vtrans, ctrans }) {} private: - void clear() noexcept override + void clear() override { container_.clear(); } @@ -246,7 +246,7 @@ namespace nana void erase(std::size_t pos) override { auto i = container_.begin(); - std::advance(i, static_cast(pos)); + std::advance(i, pos); container_.erase(i); } @@ -263,7 +263,7 @@ namespace nana void emplace(std::size_t pos) override { auto i = container_.begin(); - std::advance(i, static_cast(pos)); + std::advance(i, pos); container_.emplace(i); } @@ -327,7 +327,7 @@ namespace nana } private: - void clear() noexcept override + void clear() override { container_.clear(); } @@ -335,7 +335,7 @@ namespace nana void erase(std::size_t pos) override { auto i = container_.begin(); - std::advance(i, static_cast(pos)); + std::advance(i, pos); container_.erase(i); } @@ -352,7 +352,7 @@ namespace nana void emplace(std::size_t pos) override { auto i = container_.begin(); - std::advance(i, static_cast(pos)); + std::advance(i, pos); container_.emplace(i); } From a937c6d8c5a81167ad957b1ad591fb389406deb8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 21 Jun 2017 23:25:02 +0800 Subject: [PATCH 27/28] code refined --- source/gui/widgets/listbox.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 2dcd6f3e..078cd6c8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3441,7 +3441,7 @@ namespace nana idx.item = 0; - _m_draw_categ(*i_categ, rect.x - origin.x, item_coord.y, txtoff, header_w, rect, bgcolor, + _m_draw_categ(*i_categ, rect.x - origin.x, item_coord.y, txtoff, header_w, bgcolor, (hoverred_pos.is_category() && (idx.cat == hoverred_pos.cat) ? item_state::highlighted : item_state::normal) ); item_coord.y += static_cast(item_height_px); @@ -3500,7 +3500,7 @@ namespace nana } } private: - void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, const nana::rectangle& /*r*/, nana::color bgcolor, item_state state) + void _m_draw_categ(const category_t& categ, int x, int y, int txtoff, unsigned width, nana::color bgcolor, item_state state) { const auto item_height = essence_->item_height(); From 40c35d87a03ee0791519226ead7fcea4755e731d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 22 Jun 2017 00:11:36 +0800 Subject: [PATCH 28/28] fix compiler warnings --- source/gui/widgets/skeletons/text_editor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index d541da66..a461137e 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -2327,7 +2327,7 @@ namespace nana{ namespace widgets //move the caret to the end of the text if Ctrl is pressed if(arg.ctrl) - pos.y = (line_count - 1) * line_px; + pos.y = static_cast((line_count - 1) * line_px); break; case keyboard::os_pageup: if(origin.y > 0) @@ -2652,7 +2652,7 @@ namespace nana{ namespace widgets } //move the caret to the end of this section. - res.x = text_size; + res.x = static_cast(text_size); for (std::size_t i = 0; i < row.second; ++i) res.x += static_cast(sections[i].end - sections[i].begin);