From 19339c52399aabcf749265146b9dcc1ca8eba7ce Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 13 Mar 2015 14:39:57 +0800 Subject: [PATCH 01/49] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3546c151..c9676580 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ Nana is licensed under the [Boost Software License]. The best way to get help with Nana library is by visiting http://nanapro.org/help.htm +## Sending a Pull Request ? + +This project is encourage you to contribute it through sending a pull request! There is a simple rule, please don't directly commit your contributions to the master branch. According to your commits, please choose the hotfixes branch or the develop branch. Thank you! + ## Introduction to the Repository There are two main branches with an infinite lifetime: From 02facbd4cc8618f4a99d42e82c58b2892502d59f Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 13 Mar 2015 14:41:45 +0800 Subject: [PATCH 02/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9676580..8b85b0c2 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The best way to get help with Nana library is by visiting http://nanapro.org/hel ## Sending a Pull Request ? -This project is encourage you to contribute it through sending a pull request! There is a simple rule, please don't directly commit your contributions to the master branch. According to your commits, please choose the hotfixes branch or the develop branch. Thank you! +This project is encourage you to contribute it through sending a pull request! There is a simple rule, please **don't** directly commit your contributions to the **master** branch. According to your commits, please choose the **hotfixes** branch or the **develop** branch. Thank you! ## Introduction to the Repository From 52d040a95d2a5136f1a79d7aa25f3fc5a2637bda Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:50:30 +0200 Subject: [PATCH 03/49] FIX: trace the whole cat when selected, not just the last item --- source/gui/widgets/listbox.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 53ee6eff..a44d7d47 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1595,26 +1595,21 @@ namespace nana bool categ_selected(size_type cat, bool sel) { bool changed = false; - auto & items = _m_at(cat)->items; - index_pair pos(cat, 0); - for(auto & m : items) + cat_proxy cpx{ess_,cat}; + for (item_proxy &it : cpx ) { - if(m.flags.selected != sel) - { - m.flags.selected = sel; - - arg_listbox arg{ item_proxy(ess_, pos), sel }; - wd_ptr()->events().selected.emit(arg); + if (it.selected() != sel) changed = true; + it.select(sel); if (sel) // not check for single_selection_ - last_selected_abs = pos; - else if (last_selected_abs == pos) + last_selected_abs = it->pos(); + + else if (last_selected_abs == it->pos()) last_selected_abs.set_both(npos); } - ++pos.item; - } + last_selected_abs = index_pair{cat,npos}; return changed; } From 31639cb34d88609c562ce1f0ce116873465b2b72 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:53:27 +0200 Subject: [PATCH 04/49] to find the first item or cat --- source/gui/widgets/listbox.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index a44d7d47..2de8d4c2 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1639,7 +1639,20 @@ namespace nana /// absolute position of the last displayed item index_pair last_displ() const { - return absolute ( last_displ() ); + return absolute ( last() ); + } + + /// 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 + { + index_pair fst{0,npos}; + good_item(fst,fst); + return fst; + } + /// absolute position of the first displayed item + index_pair first_displ() const + { + return absolute ( first() ); } bool good(size_type cat) const From 65ebdccd907d81e84a92b87b59052ab04e4f4132 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:54:37 +0200 Subject: [PATCH 05/49] FIX: let check this 0,0 is good --- source/gui/widgets/listbox.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 2de8d4c2..de1a04ce 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1664,32 +1664,32 @@ namespace nana { return ((pos.cat < list_.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(index_pair pos, index_pair& item) const { if (!good(pos.cat)) - return false; + return false; // cat out of range if (pos.is_category()) { - item = pos; - if (0 == pos.cat) - item.item = 0; - + 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 = _m_at(pos.cat); + auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat if (pos.item < i->items.size()) { - item = pos; + item = pos; // good item, return it return true; } - if (++i == list_.end()) + if (++i == list_.end()) // item out of range and no more cat return false; - item.cat = pos.cat + 1; + item.cat = pos.cat + 1; // select the next cat item.item = npos; return true; } From bcb2d5b6fc002d326e56a7269dd5b5b5d0b451bc Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:55:57 +0200 Subject: [PATCH 06/49] FIX: crash if finding pos of cat --- source/gui/widgets/listbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index de1a04ce..6fc0bdd9 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1697,7 +1697,7 @@ namespace nana ///Translate relative position (position in display) into absolute position (original data order) size_type absolute(const index_pair& display_pos) const { - if(sorted_index_ == npos) + if(sorted_index_ == npos || display_pos.item == npos) return display_pos.item ; auto & catobj = *_m_at(display_pos.cat); From d4d1a79af89fbf4a3cbd390ff3cd3ee52a8b5d90 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:57:44 +0200 Subject: [PATCH 07/49] FIX: a +1 error during navigation of listbox with categories --- include/nana/gui/widgets/listbox.hpp | 1 + source/gui/widgets/listbox.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 8a2f1938..fc487460 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -366,6 +366,7 @@ namespace nana return iter; } + /// Append an item at abs end of the category, using the strins to set the columns (cells) of the new item. void append(std::initializer_list); size_type columns() const; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 6fc0bdd9..8618d4c0 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1747,13 +1747,12 @@ namespace nana return true; } - if(list_.size() <= from.cat) return false; - if(from.is_category()) { // this is a category, so... // and offs is not 0, this category would not be candidated. // the algorithm above to calc the offset item is always starting with a item. + // we can not select, navigate or highlight begining from a cat? --offs; from.item = 0; } @@ -1762,7 +1761,7 @@ namespace nana if(icat->expand) { - std::size_t item_left_in_this_cat = icat->items.size() -1- from.item; + std::size_t item_left_in_this_cat = icat->items.size()- from.item -1; if(offs <= item_left_in_this_cat ) { item = from; @@ -1771,14 +1770,15 @@ namespace nana } else { - offs -= item_left_in_this_cat ; + offs -= (item_left_in_this_cat+1) ; item = from; - item.item += item_left_in_this_cat ; + item.item += item_left_in_this_cat ;// select the last item } } ++from.cat; ++icat; + for(; icat != list_.end(); ++icat, ++from.cat) { item.cat = from.cat; @@ -2203,7 +2203,7 @@ namespace nana } else { - new_where.second = (y - header_visible_px() + 1) / item_size; + new_where.second = ((y + 1) - header_visible_px()) / item_size; // y>1 ! new_where.first = parts::lister; if(checkable) { @@ -3444,7 +3444,7 @@ namespace nana { auto i = ess_->lister.cat_container().begin(); std::advance(i, pos.cat); - cat_ = &(*i); + cat_ = &(*i); // what is pos is a cat? } } @@ -3489,7 +3489,7 @@ namespace nana /// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected item_proxy & item_proxy::select(bool s) { - auto & m = cat_->items.at(pos_.item); // a ref to the real item + auto & m = cat_->items.at(pos_.item); // a ref to the real item // what is pos is a cat? if(m.flags.selected == s) return *this; // ignore if no change m.flags.selected = s; // actually change selection From 7863dcdba63c82b7d60122ac8c6a58537460a618 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 13:59:59 +0200 Subject: [PATCH 08/49] FIX: crash in page down and home of a listbox with categories, trying to create an item_proxy {cat, npos} and select it --- source/gui/widgets/listbox.cpp | 48 ++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 8618d4c0..176b335a 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1598,17 +1598,17 @@ namespace nana cat_proxy cpx{ess_,cat}; for (item_proxy &it : cpx ) - { + { if (it.selected() != sel) - changed = true; + changed = true; it.select(sel); - if (sel) // not check for single_selection_ + if (sel) // not check for single_selection_ last_selected_abs = it->pos(); else if (last_selected_abs == it->pos()) - last_selected_abs.set_both(npos); - } + last_selected_abs.set_both(npos); + } last_selected_abs = index_pair{cat,npos}; return changed; } @@ -1653,7 +1653,7 @@ namespace nana index_pair first_displ() const { return absolute ( first() ); - } + } bool good(size_type cat) const { @@ -1676,7 +1676,7 @@ namespace nana if (0 == pos.cat) // but for cat 0 return first item item.item = 0; // let check this is good else - return true; + return true; } auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat @@ -1738,7 +1738,7 @@ namespace nana /// all arg are relative to display order, or all are absolute, but not mixed bool forward(index_pair from, size_type offs, index_pair& item) const { - if(!good_item(from, from)) + if(!good_item(from, from)) return false; if(offs == 0) @@ -1771,7 +1771,7 @@ namespace nana else { offs -= (item_left_in_this_cat+1) ; - item = from; + item = from; item.item += item_left_in_this_cat ;// select the last item } } @@ -3378,21 +3378,35 @@ namespace nana if (! scrl.make_page_scroll(!up)) return; essence_->lister.select_for_all(false); - if (up) - item_proxy {essence_, essence_->scroll_y_abs()}.select(true); - else - { - index_pair idx{essence_->scroll_y_dpl()}; + + index_pair idx{essence_->scroll_y_dpl()}; + if (!up) essence_->lister.forward(idx, scrl.range()-1, idx); - item_proxy::from_display(essence_,idx).select(true); - } + + if (idx.is_item()) + item_proxy::from_display(essence_, idx).select(true); + else + if(!essence_->lister.single_selection()) + essence_->lister.categ_selected(idx.cat, true); + + essence_->trace_last_selected_item (); + break; } case keyboard::os_home: + { essence_->lister.select_for_all(false); - item_proxy::from_display(essence_, {0,0}).select(true); + + index_pair frst{essence_->lister.first()}; + if (frst.is_item()) + item_proxy::from_display(essence_, frst).select(true); + else + if(!essence_->lister.single_selection()) + essence_->lister.categ_selected(frst.cat, true); + essence_->trace_last_selected_item (); break; + } case keyboard::os_end: essence_->lister.select_for_all(false); item_proxy::from_display(essence_, essence_->lister.last()).select(true); From 6fd15140a927e4a6a8bef4d7a1f108e9b7ab5cf0 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 May 2015 14:56:15 +0200 Subject: [PATCH 09/49] introduce cat_proxy::select(bool sel) --- include/nana/gui/widgets/listbox.hpp | 3 ++ source/gui/widgets/listbox.cpp | 57 ++++++++++++++++++---------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index fc487460..0e7d76b1 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -374,6 +374,9 @@ namespace nana cat_proxy& text(nana::string); nana::string text() const; + cat_proxy & select(bool); + bool selected() const; + /// Behavior of a container void push_back(nana::string); diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 176b335a..9e63f0f6 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1592,26 +1592,7 @@ namespace nana } /// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_ - bool categ_selected(size_type cat, bool sel) - { - bool changed = false; - - cat_proxy cpx{ess_,cat}; - for (item_proxy &it : cpx ) - { - if (it.selected() != sel) - changed = true; - it.select(sel); - - if (sel) // not check for single_selection_ - last_selected_abs = it->pos(); - - else if (last_selected_abs == it->pos()) - last_selected_abs.set_both(npos); - } - last_selected_abs = index_pair{cat,npos}; - return changed; - } + bool categ_selected(size_type cat, bool sel); void reverse_categ_selected(size_type categ) { @@ -2458,7 +2439,7 @@ namespace nana } } - nana::string es_lister::to_string(const export_options& exp_opt) const + nana::string es_lister::to_string(const export_options& exp_opt) const { nana::string list_str; bool first{true}; @@ -2479,6 +2460,22 @@ namespace nana return list_str ; } + bool es_lister::categ_selected(size_type cat, bool sel) + { + bool changed = false; // we need this?? + + cat_proxy cpx{ess_,cat}; + for (item_proxy &it : cpx ) + { + if (it.selected() != sel) + changed = true; + it.select(sel); + } + + last_selected_abs = last_selected_dpl = index_pair {cat, npos}; + + return changed; // we need this?? + } class drawer_header_impl { @@ -3737,6 +3734,24 @@ namespace nana } } + cat_proxy & cat_proxy::select(bool sel) + { + for (item_proxy &it : *this ) + it.select(sel); + + ess_->lister.last_selected_abs = + ess_->lister.last_selected_dpl = index_pair {this->pos_, npos}; + + return *this; + } + bool cat_proxy::selected() const + { + for (item_proxy &it : *this ) + if (!it.selected()) + return false; + return true; + } + auto cat_proxy::columns() const -> size_type { return ess_->header.cont().size(); From df22696e25a5736559fb0e14f397a0eb8f639dac Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 7 May 2015 22:42:04 +0200 Subject: [PATCH 10/49] comments... --- include/nana/gui/widgets/listbox.hpp | 65 +++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 0e7d76b1..01fe6ae4 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -163,9 +163,9 @@ namespace nana typedef std::vector selection; - //struct essence_t - //@brief: this struct gives many data for listbox, - // the state of the struct does not effect on member funcions, therefore all data members are public. + /// struct essence_t + ///@brief: this struct gives many data for listbox, + /// the state of the struct does not effect on member funcions, therefore all data members are public. struct essence_t; struct category_t; @@ -366,7 +366,7 @@ namespace nana return iter; } - /// Append an item at abs end of the category, using the strins to set the columns (cells) of the new item. + /// Appends one item at the end of this category with the specifies text in the column fields void append(std::initializer_list); size_type columns() const; @@ -481,12 +481,63 @@ namespace nana } }//end namespace drawerbase -/*! \brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items. +/*! \class listbox +\brief A rectangle containing a list of strings from which the user can select. This widget contain a list of \a categories, with in turn contain a list of \a items. A category is a text with can be \a selected, \a checked and \a expanded to show the items. An item is formed by \a column-fields, each corresponding to one of the \a headers. An item can be \a selected and \a checked. -The user can \a drag the header to \a reisize it or to \a reorganize it. -By \a clicking on a header the list get \a reordered, first up, and then down alternatively. +The user can \a drag the header to \a resize it or to \a reorganize it. +By \a clicking on one header the list get \a reordered, first up, and then down alternatively. + +1. The resolver is used to resolute an object of the specified type for a listbox item. +2. The any_objective of listbox have a 2-Dimension indexing. The first dimension is for the category, and the second one is for the item of the specified category. + int main() + { + using namespace nana::gui; + form fm; + listbox lb(fm, nana::rectangle(10, 10, 280, 120)); + lb.append_header(STR("Header"), 200); + lb.append_item(STR("int")); + lb.append_item(STR("double")); + lb.anyobj(0, 0, 10); + lb.anyobj(0, 1, 0.1); + int * pi = lb.anyobj(0, 0); // it returns a nullptr if there is not an int object specified. + double * pd = lb.anyobj(0, 1); // it returns a nullptr if there is not an double object specified. + fm.show(); + exec(); + } +3. nana::listbox creates the category 0 by default. The member functions without the categ parameter operate the items that belong to category 0. +4. A sort compare is used for sorting the items. It is a strict weak ordering comparer that must meet the requirement: + Irreflexivity (comp(x, x) returns false) + and + antisymmetry(comp(a, b) != comp(b, a) returns true) + A simple example. + bool sort_compare( const nana::string& s1, nana::any*, + const nana::string& s2, nana::any*, bool reverse) + { + return (reverse ? s1 > s2 : s1 < s2); + } + listbox.set_sort_compare(0, sort_compare); + The listbox supports attaching a customer's object for each item, therefore the items can be + sorted by comparing these customer's object. + bool sort_compare( const nana::string&, nana::any* o1, + const nana::string&, nana::any* o2, bool reverse) + { + if(o1 && o2) //some items may not attach a customer object. + { + int * i1 = o1->get(); + int * i2 = o2->get(); + return (i1 && i2 && (reverse ? *i1 > *i2 : *i1 < *i2)); + ;//some types may not be int. + } + return false; + } + listbox.anyobj(0, 0, 10); //the type of customer's object is int. + listbox.anyobj(0, 0, 20); +\todo doc: actualize this example listbox.at(0)... +\see nana::drawerbase::listbox::cat_proxy +\see nana::drawerbase::listbox::item_proxy +\example listbox_Resolver.cpp */ class listbox : public widget_object, From 444449dfaa24172b6e8f609eea96bdcdc176cf53 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 7 May 2015 22:48:20 +0200 Subject: [PATCH 11/49] let listbox append_header return the pos of the new header --- include/nana/gui/widgets/listbox.hpp | 3 ++- source/gui/widgets/listbox.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 01fe6ae4..34046a6f 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -561,9 +561,10 @@ By \a clicking on one header the list get \a reordered, first up, and then down void auto_draw(bool); ///); ///(cont_.size())); + return cont_.back().index; } void item_width(size_type pos, unsigned width) { - if (pos >= cont_.size()) - return; - for(auto & m : cont_) - { if(m.index == pos) + { m.pixels = width; + return; } } @@ -3994,11 +3993,12 @@ namespace nana _m_ess().set_auto_draw(ad); } - void listbox::append_header(nana::string text, unsigned width) + listbox::size_type listbox::append_header(nana::string text, unsigned width) { auto & ess = _m_ess(); - ess.header.create(std::move(text), width); + listbox::size_type index = ess.header.create(std::move(text), width); ess.update(); + return index; } listbox& listbox::header_width(size_type pos, unsigned pixels) From 371633f23f7fabf0dc7c263bc230d5f2787ee3c4 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 7 May 2015 22:50:26 +0200 Subject: [PATCH 12/49] listbox auto_width set the column width to fit the current longest text --- include/nana/gui/widgets/listbox.hpp | 14 ++++++++------ source/gui/widgets/listbox.cpp | 20 +++++++++++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 34046a6f..ca4bb8ed 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -367,7 +367,7 @@ namespace nana } /// Appends one item at the end of this category with the specifies text in the column fields - void append(std::initializer_list); + void append(std::initializer_list); size_type columns() const; @@ -559,15 +559,17 @@ By \a clicking on one header the list get \a reordered, first up, and then down listbox(window, bool visible); listbox(window, const rectangle& = {}, bool visible = true); - void auto_draw(bool); ///); ///); ///< Appends categories at the end cat_proxy insert(cat_proxy, nana::string); cat_proxy at(size_type pos) const; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 8a979678..3588576f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -412,7 +412,7 @@ namespace nana { m.pixels = width; return; - } + } } unsigned item_width(size_type pos) const @@ -4008,6 +4008,24 @@ namespace nana ess.update(); return *this; } + unsigned listbox::auto_width(size_type pos, unsigned max) + { + unsigned max_w{0}; + auto & ess = _m_ess(); + for (const auto &cat : ess.lister.cat_container()) + for (const auto &it : cat.items ) + { + if (pos >= it.cells.size()) continue; + // precalcule text geometry + unsigned ts = static_cast ( ess.graph->text_extent_size(it.cells[pos].text).width); + if (max_w < ts) + max_w = ts; + } + if (!max_w) return 0; + header_width(pos, max_w < max ? max_w : max); + ess.update(); + return max_w; + } unsigned listbox::header_width(size_type pos) const { From e696fff7791f1dcf3f92cdaff0ae30d88f8b7bc3 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 8 May 2015 00:31:32 +0200 Subject: [PATCH 13/49] implement double click to auto resize a column in listbox --- include/nana/gui/widgets/listbox.hpp | 19 ++--------- source/gui/widgets/listbox.cpp | 47 +++++++++++++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index ca4bb8ed..87309008 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -477,6 +477,9 @@ namespace nana color_proxy header_grabbed{ static_cast(0x8BD6F6)}; color_proxy header_floated{ static_cast(0xBABBBC)}; color_proxy item_selected{ static_cast(0xD5EFFC) }; + + unsigned max_header_width{3000}, /// \todo how to implement some geometrical parameters ?? + ext_w = 5; }; } }//end namespace drawerbase @@ -490,22 +493,6 @@ The user can \a drag the header to \a resize it or to \a reorganize it. By \a clicking on one header the list get \a reordered, first up, and then down alternatively. 1. The resolver is used to resolute an object of the specified type for a listbox item. -2. The any_objective of listbox have a 2-Dimension indexing. The first dimension is for the category, and the second one is for the item of the specified category. - int main() - { - using namespace nana::gui; - form fm; - listbox lb(fm, nana::rectangle(10, 10, 280, 120)); - lb.append_header(STR("Header"), 200); - lb.append_item(STR("int")); - lb.append_item(STR("double")); - lb.anyobj(0, 0, 10); - lb.anyobj(0, 1, 0.1); - int * pi = lb.anyobj(0, 0); // it returns a nullptr if there is not an int object specified. - double * pd = lb.anyobj(0, 1); // it returns a nullptr if there is not an double object specified. - fm.show(); - exec(); - } 3. nana::listbox creates the category 0 by default. The member functions without the categ parameter operate the items that belong to category 0. 4. A sort compare is used for sorting the items. It is a strict weak ordering comparer that must meet the requirement: Irreflexivity (comp(x, x) returns false) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 3588576f..9c8eccf7 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2304,7 +2304,29 @@ namespace nana break; } } - private: + + unsigned auto_width(size_type pos, unsigned max=3000) /// \todo introduce parametr max_header_width + { + unsigned max_w{0} ; + for (const auto &cat : lister.cat_container()) + for (const auto &it : cat.items ) + { + if (pos >= it.cells.size()) continue; + // precalcule text geometry + unsigned ts = static_cast ( graph->text_extent_size(it.cells[pos].text).width); + if (max_w < ts) + max_w = ts; + } + if (!max_w) return 0; + + unsigned ext_w = scheme_ptr->ext_w ; + if( pos == 0 && checkable) // only before the first column (display_order=0 ?) + ext_w += 18; + header.item_width(pos, max_w + ext_w + 1 < max ? max_w + ext_w + 1 : max); + return max_w; + } + + private: void _m_answer_scroll(const arg_mouse& arg) { if(arg.evt_code == event_code::mouse_move && arg.left_button == false) return; @@ -2907,7 +2929,7 @@ namespace nana cell_txtcolor = m_cell.custom_format->fgcolor; } - int ext_w = 5; + int ext_w = essence_->scheme_ptr->ext_w; if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?) { ext_w += 18; @@ -3306,6 +3328,14 @@ namespace nana void trigger::dbl_click(graph_reference graph, const arg_mouse&) { + if (essence_->pointer_where.first == essence_t::parts::header) + if (cursor::size_we == essence_->lister.wd_ptr()->cursor()) + { + if (essence(). auto_width(drawer_header_->item_spliter() )) // ? in order + essence().update(); + return; + } + if (essence_->pointer_where.first != essence_t::parts::lister) return; @@ -4010,19 +4040,8 @@ namespace nana } unsigned listbox::auto_width(size_type pos, unsigned max) { - unsigned max_w{0}; auto & ess = _m_ess(); - for (const auto &cat : ess.lister.cat_container()) - for (const auto &it : cat.items ) - { - if (pos >= it.cells.size()) continue; - // precalcule text geometry - unsigned ts = static_cast ( ess.graph->text_extent_size(it.cells[pos].text).width); - if (max_w < ts) - max_w = ts; - } - if (!max_w) return 0; - header_width(pos, max_w < max ? max_w : max); + unsigned max_w = ess.auto_width(pos, max); ess.update(); return max_w; } From f0f6246ccc7acf2b7f4b77fe38d0126d8a268086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rajko=20=C4=90or=C4=91evi=C4=87?= Date: Sun, 10 May 2015 12:01:35 +0200 Subject: [PATCH 14/49] Letting cmake to decide which standard to use, if compiler doesn't support c++14 it will fall back to c++11 as was before. --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dba9e2c9..242a1ea2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,7 @@ execute_process(COMMAND ${CMAKE_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR}/include/nana/) if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(NANA_SOURCE_DIR ${CMAKE_SOURCE_DIR}/source) @@ -161,3 +161,5 @@ install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) install(DIRECTORY ${NANA_INCLUDE_DIR}/nana DESTINATION include) + +set_property( TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14 ) From f4ceafbe6cc48bd31947f59aed2d59fb57110489 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 10 May 2015 15:28:59 +0200 Subject: [PATCH 15/49] testing and doxy comment audio and screen --- include/nana/audio/player.hpp | 5 ++++- include/nana/gui/screen.hpp | 17 ++++++++++++++--- source/audio/detail/audio_stream.cpp | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/nana/audio/player.hpp b/include/nana/audio/player.hpp index 278e0ecc..24378214 100644 --- a/include/nana/audio/player.hpp +++ b/include/nana/audio/player.hpp @@ -4,7 +4,10 @@ #include namespace nana{ namespace audio -{ /// play an audio file in Windows WAV format +{ /// class player + /// \brief play an audio file in PCM Windows WAV format + /// + /// \include audio_player.cpp class player : private nana::noncopyable { diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp index ef9126e8..06c344ee 100644 --- a/include/nana/gui/screen.hpp +++ b/include/nana/gui/screen.hpp @@ -34,27 +34,38 @@ namespace nana virtual const ::nana::rectangle& workarea() const = 0; }; + /// Provides some functions to get the metrics of the monitors \include screen.cpp class screen { struct implement; public: - static ::nana::size desktop_size(); - static ::nana::size primary_monitor_size(); + /// gets the size in pixel of the whole virtual desktop + static ::nana::size desktop_size(); + + /// gets the resolution in pixel of the primary monitor, + /// if there is only one monitor installed in the system, + /// the return value of primary_monitor_size is equal to desktop_size's. + static ::nana::size primary_monitor_size(); + screen(); /// Reload has no preconditions, it's safe to call on moved-from void reload(); - /// Returns the number of display monitors + /// Returns the number of display monitors installed in the system std::size_t count() const; + /// gets the display monitor that contains the specified point display& from_point(const point&); + + /// gets the display monitor that contains the specified window display& from_window(window); display& get_display(std::size_t index) const; display& get_primary() const; + /// applies a given function to all display monitors void for_each(std::function) const; private: std::shared_ptr impl_; diff --git a/source/audio/detail/audio_stream.cpp b/source/audio/detail/audio_stream.cpp index 96def3d9..998b85bf 100644 --- a/source/audio/detail/audio_stream.cpp +++ b/source/audio/detail/audio_stream.cpp @@ -8,7 +8,8 @@ namespace nana{ namespace audio //class audio_stream bool audio_stream::open(const nana::string& file) { - fs_.open(static_cast(nana::charset(file)), std::ios::binary); + std::string fname{nana::charset(file)};//static_cast() + fs_.open(fname, std::ios::binary); if(fs_) { wave_spec::master_riff_chunk riff; From 7117cc03b0276c5dd110ec390aa8fedb989f1ede Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 20 May 2015 12:42:53 +0200 Subject: [PATCH 16/49] adapting nana filesystem to std --- build/vc2013/nana.vcxproj | 3 + build/vc2013/nana.vcxproj.filters | 5 + include/nana/filesystem/filesystem.hpp | 272 +++++++++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 include/nana/filesystem/filesystem.hpp diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 7e216758..5f16d613 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -247,6 +247,9 @@ + + + diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index f0f82981..1b098164 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -301,4 +301,9 @@ Source Files\nana\gui\widgets + + + Header Files + + \ No newline at end of file diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp new file mode 100644 index 00000000..bfdd1a71 --- /dev/null +++ b/include/nana/filesystem/filesystem.hpp @@ -0,0 +1,272 @@ +/* + * A filesystem Implementation + * Copyright(C) 2003 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: stdex/filesystem/filesystem.hpp + * @description: + * file_iterator is a toolkit for applying each file and directory in a + * specified path. + */ + +// http://en.cppreference.com/w/cpp/experimental/fs +// http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/ --- TR2 filesystem in VS2012 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.140%29.aspx --- C++ 14, the header VS2015 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.120%29.aspx --- header VS2013 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- last pdf of std draft N4100 2014-07-04 +// http://cplusplus.github.io/filesystem-ts/working-draft.html --- in html format +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4099.html --- in html format +// http://article.gmane.org/gmane.comp.lib.boost.devel/256220 --- The filesystem TS unanimously approved by ISO. +// http://theboostcpplibraries.com/boost.filesystem --- Boost docs +// http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm --- +// http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm +// http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp + + +#ifndef NANA_FILESYSTEM_HPP +#define NANA_FILESYSTEM_HPP +#include +#include + +#include + +#ifdef NANA_WINDOWS + #include + typedef HANDLE find_handle_t; +#elif defined(NANA_LINUX) + #include + #include + #include + typedef DIR* find_handle_t; +#endif + + // namespace std { namespace experimental { namespace filesystem { inline namespace v1 { + +namespace nana +{ +namespace filesystem +{ + struct fileinfo + { + fileinfo(); +#ifdef NANA_WINDOWS + fileinfo(const WIN32_FIND_DATA& wfd); +#elif NANA_LINUX + fileinfo(const nana::string& filename, const struct stat &); +#endif + nana::string name; + + unsigned long size; + bool directory; + }; + + + /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator + //template + class directory_iterator :public std::iterator + { + public: + typedef fileinfo value_type; + + directory_iterator():end_(true), handle_(nullptr){} + + directory_iterator(const nana::string& file_path) + :end_(false), handle_(nullptr) + { + _m_prepare(file_path); + } + + const value_type& + operator*() const { return value_; } + + const value_type* + operator->() const { return &(operator*()); } + + directory_iterator& operator++() + { _m_read(); return *this; } + + directory_iterator operator++(int) + { + directory_iterator tmp = *this; + _m_read(); + return tmp; + } + + bool equal(const directory_iterator& x) const + { + if(end_ && (end_ == x.end_)) return true; + return (value_.name == x.value_.name); + } + private: + template + static bool _m_ignore(const Char * p) + { + while(*p == '.') + ++p; + return (*p == 0); + } + + void _m_prepare(const nana::string& file_path) + { + #if defined(NANA_WINDOWS) + path_ = file_path; + auto pat = file_path; + DWORD attr = ::GetFileAttributes(pat.data()); + if((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) + pat += STR("\\*"); + + ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd_); + + if(handle == INVALID_HANDLE_VALUE) + { + end_ = true; + return; + } + + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle, &wfd_) == 0) + { + end_ = true; + ::FindClose(handle); + return; + } + } + value_ = value_type(wfd_); + #elif defined(NANA_LINUX) + path_ = nana::charset(file_path); + if(path_.size() && (path_[path_.size() - 1] != '/')) + path_ += '/'; + find_handle_t handle = opendir(path_.c_str()); + end_ = true; + if(handle) + { + struct dirent * dnt = readdir(handle); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle); + if(dnt == 0) + { + closedir(handle); + return; + } + } + + struct stat fst; + if(stat((path_ + dnt->d_name).c_str(), &fst) == 0) + { + value_ = value_type(nana::charset(dnt->d_name), fst); + } + else + { + value_.name = nana::charset(dnt->d_name); + value_.size = 0; + value_.directory = false; + } + end_ = false; + } + } + #endif + if(false == end_) + { + find_ptr_ = std::shared_ptr(new find_handle_t(handle), inner_handle_deleter()); + handle_ = handle; + } + } + + void _m_read() + { + if(handle_) + { + #if defined(NANA_WINDOWS) + if(::FindNextFile(handle_, &wfd_) != 0) + { + while(_m_ignore(wfd_.cFileName)) + { + if(::FindNextFile(handle_, &wfd_) == 0) + { + end_ = true; + return; + } + } + value_ = value_type(wfd_); + } + else + end_ = true; + #elif defined(NANA_LINUX) + struct dirent * dnt = readdir(handle_); + if(dnt) + { + while(_m_ignore(dnt->d_name)) + { + dnt = readdir(handle_); + if(dnt == 0) + { + end_ = true; + return; + } + } + struct stat fst; + if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0) + value_ = value_type(nana::charset(dnt->d_name), fst); + else + value_.name = nana::charset(dnt->d_name); + } + else + end_ = true; + #endif + } + } + private: + struct inner_handle_deleter + { + void operator()(find_handle_t * handle) + { + if(handle && *handle) + { + #if defined(NANA_WINDOWS) + ::FindClose(*handle); + #elif defined(NANA_LINUX) + ::closedir(*handle); + #endif + } + delete handle; + } + }; + private: + bool end_; + +#if defined(NANA_WINDOWS) + WIN32_FIND_DATA wfd_; + nana::string path_; +#elif defined(NANA_LINUX) + std::string path_; +#endif + std::shared_ptr find_ptr_; + + find_handle_t handle_; + value_type value_; + }; + + //template + inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y) + { + return x.equal(y); + } + + //template + inline bool operator!=(const directory_iterator/**/ & x, const directory_iterator/**/ & y) + { + return !x.equal(y); + } + + //using directory_iterator = directory_iterator ; +}//end namespace filesystem +}//end namespace nana + +#endif From 0b63ca51f7153270b2df657aea9013f9074656c8 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 21 May 2015 15:43:14 +0200 Subject: [PATCH 17/49] mimic std directory_iterator and directory_entry --- include/nana/filesystem/filesystem.hpp | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index bfdd1a71..f71504b7 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -24,7 +24,7 @@ // http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm --- // http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm // http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp - +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x --- Table 1.4. g++ C++ Technical Specifications Implementation Status #ifndef NANA_FILESYSTEM_HPP #define NANA_FILESYSTEM_HPP @@ -49,16 +49,18 @@ namespace nana { namespace filesystem { - struct fileinfo - { - fileinfo(); -#ifdef NANA_WINDOWS - fileinfo(const WIN32_FIND_DATA& wfd); -#elif NANA_LINUX - fileinfo(const nana::string& filename, const struct stat &); -#endif - nana::string name; + using path = nana::string; + struct directory_entry + { + directory_entry(); + directory_entry(const nana::string& filename, bool is_directory, unsigned long size) + :name{filename}, size{size}, directory{is_directory} + {} + const path& path() const noexcept{return name;} + //operator const path&() const noexcept; + + nana::string name; unsigned long size; bool directory; }; @@ -66,10 +68,10 @@ namespace filesystem /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator //template - class directory_iterator :public std::iterator + class directory_iterator :public std::iterator { public: - typedef fileinfo value_type; + using value_type = directory_entry ; directory_iterator():end_(true), handle_(nullptr){} @@ -135,7 +137,11 @@ namespace filesystem return; } } - value_ = value_type(wfd_); + + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); + #elif defined(NANA_LINUX) path_ = nana::charset(file_path); if(path_.size() && (path_[path_.size() - 1] != '/')) @@ -160,7 +166,7 @@ namespace filesystem struct stat fst; if(stat((path_ + dnt->d_name).c_str(), &fst) == 0) { - value_ = value_type(nana::charset(dnt->d_name), fst); + value_ = value_type(nana::charset(dnt->d_name), 0 != S_ISDIR(fst.st_mode), fst.st_size); } else { @@ -194,7 +200,9 @@ namespace filesystem return; } } - value_ = value_type(wfd_); + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); } else end_ = true; @@ -213,7 +221,9 @@ namespace filesystem } struct stat fst; if(stat((path_ + "/" + dnt->d_name).c_str(), &fst) == 0) - value_ = value_type(nana::charset(dnt->d_name), fst); + value_ = value_type(wfd_.cFileName, + (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, + wfd_.nFileSizeLow); else value_.name = nana::charset(dnt->d_name); } @@ -265,7 +275,7 @@ namespace filesystem return !x.equal(y); } - //using directory_iterator = directory_iterator ; + //using directory_iterator = directory_iterator ; }//end namespace filesystem }//end namespace nana From 02961f16737594f8620dcd4f869288c3fabb115f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 21 May 2015 22:06:14 +0200 Subject: [PATCH 18/49] add file_type (from type), bring all from fs_utility and mimic path, and directory_entry --- build/vc2013/nana.vcxproj | 1 + build/vc2013/nana.vcxproj.filters | 3 + include/nana/filesystem/filesystem.hpp | 81 ++++- source/filesystem/filesystem.cpp | 442 +++++++++++++++++++++++++ 4 files changed, 517 insertions(+), 10 deletions(-) create mode 100644 source/filesystem/filesystem.cpp diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 5f16d613..9547b689 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -177,6 +177,7 @@ + diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index 1b098164..cb51dab8 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -300,6 +300,9 @@ Source Files\nana\gui\widgets + + Source Files\nana\filesystem + diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index f71504b7..1f387006 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -49,20 +49,81 @@ namespace nana { namespace filesystem { - using path = nana::string; + enum class file_type + { + none = 0, ///< has not been determined or an error occurred while trying to determine + not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error + regular = 1, + directory = 2 , + symlink =3, ///< Symbolic link file + block =4, ///< Block special file + character= 5 , ///< Character special file + fifo = 6 , ///< FIFO or pipe file + socket =7, + unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other + }; + + enum class error { none = 0 }; + + struct attribute + { + long long bytes; + bool is_directory; + tm modified; + }; + + bool file_attrib(const nana::string& file, attribute&); + long long filesize(const nana::string& file); + + bool mkdir(const nana::string& dir, bool & if_exist); + bool modified_file_time(const nana::string& file, struct tm&); + + nana::string path_user(); + nana::string path_current(); + + bool rmfile(const nana::char_t* file); + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); + nana::string root(const nana::string& path); + + /// concerned only with lexical and syntactic aspects and does not necessarily exist in + /// external storage, and the pathname is not necessarily valid for the current operating system + /// or for a particular file system + /// A sequence of elements that identify the location of a file within a filesystem. + /// The elements are the: + /// rootname (opt), root-directory (opt), and an optional sequence of filenames. + /// The maximum number of elements in the sequence is operating system dependent. + class path + { + public: + path(); + path(const nana::string&); + + bool empty() const; + path root() const; + file_type what() const; + + nana::string name() const; + private: +#if defined(NANA_WINDOWS) + nana::string text_; +#else + std::string text_; +#endif + }; struct directory_entry { - directory_entry(); - directory_entry(const nana::string& filename, bool is_directory, unsigned long size) - :name{filename}, size{size}, directory{is_directory} - {} - const path& path() const noexcept{return name;} - //operator const path&() const noexcept; - - nana::string name; + path m_path; unsigned long size; bool directory; + + directory_entry(); + directory_entry(const nana::string& filename, bool is_directory, unsigned long size) + :m_path{filename}, size{size}, directory{is_directory} + {} + operator const path&() const noexcept; + const path& path() const noexcept{return m_path;} + }; @@ -100,7 +161,7 @@ namespace filesystem bool equal(const directory_iterator& x) const { if(end_ && (end_ == x.end_)) return true; - return (value_.name == x.value_.name); + return (value_.path().name() == x.value_.path().name()); } private: template diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp new file mode 100644 index 00000000..e79f786a --- /dev/null +++ b/source/filesystem/filesystem.cpp @@ -0,0 +1,442 @@ +/* + * A FileSystem Utility Implementation + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/filesystem/filesystem.cpp + * @description: + * provide some interface for file managment + */ + +#include +#include +#if defined(NANA_WINDOWS) + #include + + #if defined(NANA_MINGW) + #ifndef _WIN32_IE + #define _WIN32_IE 0x0500 + #endif + #endif + + #include + #include +#elif defined(NANA_LINUX) + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace nana +{ +namespace filesystem +{ +//Because of No wide character version of POSIX +#if defined(NANA_LINUX) + typedef std::string string_t; + const char* splstr = "/\\"; +#else + typedef nana::string string_t; + const nana::char_t* splstr = STR("/\\"); +#endif + //class path + path::path(){} + + path::path(const nana::string& text) +#if defined(NANA_WINDOWS) + :text_(text) + { +#else + :text_(nana::charset(text)) + { +#endif + auto pos = text_.find_last_of(splstr); + for(; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) + text_.erase(pos); + } + + bool path::empty() const + { +#if defined(NANA_WINDOWS) + return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); +#elif defined(NANA_LINUX) + struct stat sta; + return (::stat(text_.c_str(), &sta) == -1); +#endif + } + + path path::root() const + { + #if defined(NANA_WINDOWS) + return path(filesystem::root(text_)); + #elif defined(NANA_LINUX) + return path(filesystem::root(nana::charset(text_))); + #endif + } + + file_type path::what() const + { +#if defined(NANA_WINDOWS) + unsigned long attr = ::GetFileAttributes(text_.c_str()); + if(INVALID_FILE_ATTRIBUTES == attr) + return file_type:: not_found ; //?? + + if(FILE_ATTRIBUTE_DIRECTORY & attr) + return file_type::directory; + + return file_type::regular; +#elif defined(NANA_LINUX) + struct stat sta; + if(-1 == ::stat(text_.c_str(), &sta)) + return file_type:: not_found ; //?? + + if((S_IFDIR & sta.st_mode) == S_IFDIR) + return file_type::directory; + + if((S_IFREG & sta.st_mode) == S_IFREG) + return file_type::regular; + + return file_type::none; +#endif + } + + nana::string path::name() const + { + string_t::size_type pos = text_.find_last_of(splstr); +#if defined(NANA_WINDOWS) + return text_.substr(pos + 1); +#else + return nana::charset(text_.substr(pos + 1)); +#endif + } + //end class path + + namespace detail + { + //rm_dir_recursive + //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories + bool rm_dir_recursive(nana::string&& dir) + { + std::vector files; + nana::string path = dir; + path += '\\'; + + std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); + + for(auto & f : files) + { + if(f.directory) + rm_dir_recursive(path + f.path().name()); + else + rmfile((path + f.path().name()).c_str()); + } + + return rmdir(dir.c_str(), true); + } + + bool mkdir_helper(const nana::string& dir, bool & if_exist) + { +#if defined(NANA_WINDOWS) + if(::CreateDirectory(dir.c_str(), 0)) + { + if_exist = false; + return true; + } + + if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); +#elif defined(NANA_LINUX) + if(0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) + { + if_exist = false; + return true; + } + + if_exist = (errno == EEXIST); +#endif + return false; + } + +#if defined(NANA_WINDOWS) + void filetime_to_c_tm(FILETIME& ft, struct tm& t) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&ft, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + } + } +#endif + }//end namespace detail + + bool file_attrib(const nana::string& file, attribute& attr) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA fad; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) + { + LARGE_INTEGER li; + li.u.LowPart = fad.nFileSizeLow; + li.u.HighPart = fad.nFileSizeHigh; + attr.bytes = li.QuadPart; + attr.is_directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); + return true; + } +#elif defined(NANA_LINUX) + struct stat fst; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) + { + attr.bytes = fst.st_size; + attr.is_directory = (0 != (040000 & fst.st_mode)); + attr.modified = *(::localtime(&fst.st_ctime)); + return true; + } +#endif + return false; + } + + long long filesize(const nana::string& file) + { +#if defined(NANA_WINDOWS) + //Some compilation environment may fail to link to GetFileSizeEx + typedef BOOL (__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); + GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); + if(get_file_size_ex) + { + HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if(INVALID_HANDLE_VALUE != handle) + { + LARGE_INTEGER li; + if(!get_file_size_ex(handle, &li)) + li.QuadPart = 0; + + ::CloseHandle(handle); + return li.QuadPart; + } + } + return 0; +#elif defined(NANA_LINUX) + FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); + long long size = 0; + if(stream) + { + fseeko64(stream, 0, SEEK_END); + size = ftello64(stream); + fclose(stream); + } + return size; +#endif + } + + bool modified_file_time(const nana::string& file, struct tm& t) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA attr; + if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) + { + FILETIME local_file_time; + if(::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + return true; + } + } +#elif defined(NANA_LINUX) + struct stat attr; + if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) + { + t = *(::localtime(&attr.st_ctime)); + return true; + } +#endif + return false; + } + + bool mkdir(const nana::string& path, bool & if_exist) + { + if_exist = false; + if(path.size() == 0) return false; + + nana::string root; +#if defined(NANA_WINDOWS) + if(path.size() > 3 && path[1] == STR(':')) + root = path.substr(0, 3); +#elif defined(NANA_LINUX) + if(path[0] == STR('/')) + root = '/'; +#endif + bool mkstat = false; + std::size_t beg = root.size(); + + while(true) + { + beg = path.find_first_not_of(STR("/\\"), beg); + if(beg == path.npos) + break; + + std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); + if(pos != path.npos) + { + root += path.substr(beg, pos - beg); + + mkstat = detail::mkdir_helper(root, if_exist); + if(mkstat == false && if_exist == false) + return false; + +#if defined(NANA_WINDOWS) + root += STR('\\'); +#elif defined(NANA_LINUX) + root += STR('/'); +#endif + } + else + { + if(beg + 1 < path.size()) + { + root += path.substr(beg); + mkstat = detail::mkdir_helper(root, if_exist); + } + break; + } + beg = pos + 1; + } + return mkstat; + } + + bool rmfile(const nana::char_t* file) + { +#if defined(NANA_WINDOWS) + bool ret = false; + if(file) + { + ret = (::DeleteFile(file) == TRUE); + if(!ret) + ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); + } + + return ret; +#elif defined(NANA_LINUX) + if(std::remove(static_cast(nana::charset(file)).c_str())) + return (errno == ENOENT); + return true; +#endif + } + + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) + { + bool ret = false; + if(dir) + { +#if defined(NANA_WINDOWS) + ret = (::RemoveDirectory(dir) == TRUE); + if(!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) + ret = detail::rm_dir_recursive(dir); +#elif defined(NANA_LINUX) + std::string mbstr = nana::charset(dir); + if(::rmdir(mbstr.c_str())) + { + if(!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) + ret = detail::rm_dir_recursive(dir); + } + else + ret = true; +#endif + } + return ret; + } + + nana::string root(const nana::string& path) + { + std::size_t index = path.size(); + + if(index) + { + const nana::char_t * str = path.c_str(); + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c != '\\' && c != '/') + break; + } + + for(--index; index > 0; --index) + { + nana::char_t c = str[index]; + if(c == '\\' || c == '/') + break; + } + } + + return index?path.substr(0, index + 1):nana::string(); + } + + nana::string path_user() + { +#if defined(NANA_WINDOWS) + nana::char_t path[MAX_PATH]; + if(SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) + return path; +#elif defined(NANA_LINUX) + const char * s = ::getenv("HOME"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + + nana::string path_current() + { +#if defined(NANA_WINDOWS) + nana::char_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); + if(len) + { + if(len > MAX_PATH) + { + nana::char_t * p = new nana::char_t[len + 1]; + ::GetCurrentDirectory(len + 1, p); + nana::string s = p; + delete [] p; + return s; + } + return buf; + } +#elif defined(NANA_LINUX) + const char * s = ::getenv("PWD"); + if(s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } +}//end namespace filesystem +}//end namespace nana From 59f0ace35397c49bd47d7b8f1912cf96d505e129 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 00:19:13 +0200 Subject: [PATCH 19/49] mimic enum class perms , more adaption --- include/nana/filesystem/filesystem.hpp | 165 +++++++++++++++++++++---- source/filesystem/filesystem.cpp | 12 +- 2 files changed, 144 insertions(+), 33 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 1f387006..3b8f3dd7 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -30,6 +30,7 @@ #define NANA_FILESYSTEM_HPP #include #include +#include #include @@ -63,27 +64,62 @@ namespace filesystem unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other }; + enum class perms + { + none =0, ///< There are no permissions set for the file. + unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions + }; + //enum class copy_options; + //enum class directory_options; + + // class filesystem_error; enum class error { none = 0 }; - struct attribute + struct attribute // deprecate ?? { - long long bytes; - bool is_directory; - tm modified; + uintmax_t size {}; + bool directory{}; + tm modified {}; + + attribute() {} ; + attribute( uintmax_t size, bool is_directory) :size{size}, directory{is_directory} {} }; - bool file_attrib(const nana::string& file, attribute&); - long long filesize(const nana::string& file); + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + using file_time_type = std::chrono::time_point< std::chrono::system_clock>;// trivial-clock> ; - bool mkdir(const nana::string& dir, bool & if_exist); - bool modified_file_time(const nana::string& file, struct tm&); + class file_status + { + file_type m_ft = file_type::none; + perms m_prms = perms::unknown; - nana::string path_user(); - nana::string path_current(); + public: + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept + :m_ft{ft}, m_prms{prms} + {} - bool rmfile(const nana::char_t* file); - bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); - nana::string root(const nana::string& path); + file_status(const file_status& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(file_status&& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + + ~file_status(){}; + file_status& operator=(const file_status&) noexcept = default; + file_status& operator=(file_status&&fs) noexcept // = default; + { + m_ft=fs.m_ft; m_prms = fs.m_prms; + return *this; + } + // observers + file_type type() const noexcept{ return m_ft;} + perms permissions() const noexcept{ return m_prms;} + // modifiers + void type (file_type ft) noexcept { m_ft=ft ;} + void permissions(perms prms) noexcept { m_prms = prms; } + }; /// concerned only with lexical and syntactic aspects and does not necessarily exist in /// external storage, and the pathname is not necessarily valid for the current operating system @@ -114,33 +150,40 @@ namespace filesystem struct directory_entry { path m_path; - unsigned long size; - bool directory; + + attribute attr{}; + //file_status m_status; directory_entry(); - directory_entry(const nana::string& filename, bool is_directory, unsigned long size) - :m_path{filename}, size{size}, directory{is_directory} + directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) + :m_path{filename}, attr{size, is_directory} {} - operator const path&() const noexcept; + + void assign (const path& p){ m_path=p;} + void replace_filename(const path& p){ m_path=p;} + + //file_status status() const; + + operator const path&() const noexcept{return m_path;}; const path& path() const noexcept{return m_path;} }; - /// an iterator for a sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator //template class directory_iterator :public std::iterator { public: using value_type = directory_entry ; + typedef ptrdiff_t difference_type; + typedef const directory_entry* pointer; + typedef const directory_entry& reference; + typedef std::input_iterator_tag iterator_category; directory_iterator():end_(true), handle_(nullptr){} - directory_iterator(const nana::string& file_path) - :end_(false), handle_(nullptr) - { - _m_prepare(file_path); - } + directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } + directory_iterator(const path& file_path) { _m_prepare(file_path.name()); } const value_type& operator*() const { return value_; } @@ -310,7 +353,7 @@ namespace filesystem } }; private: - bool end_; + bool end_{false}; #if defined(NANA_WINDOWS) WIN32_FIND_DATA wfd_; @@ -320,10 +363,19 @@ namespace filesystem #endif std::shared_ptr find_ptr_; - find_handle_t handle_; + find_handle_t handle_{nullptr}; value_type value_; }; + // enable directory_iterator range-based for statements + directory_iterator begin(directory_iterator iter) noexcept { return iter; } + directory_iterator end(const directory_iterator&) noexcept { return {}; } + + //class recursive_directory_iterator; + //// enable recursive_directory_iterator range-based for statements + //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + //template inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y) { @@ -336,7 +388,66 @@ namespace filesystem return !x.equal(y); } - //using directory_iterator = directory_iterator ; + + // file_status status(const path& p); + bool file_attrib(const nana::string& file, attribute&); + + bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + //bool is_directory(const path& p, error_code& ec) noexcept; + + //bool is_regular_file(file_status s) noexcept; + + bool is_empty(const path& p) + { + directory_iterator d(p) ; + return d->attr.directory ? d == directory_iterator() + : d->attr.size == 0; + } + //bool is_empty(const path& p, error_code& ec) noexcept; + + uintmax_t file_size(const nana::string& file); // deprecate? + uintmax_t file_size(const path& p){return file_size(p.name());} + //uintmax_t file_size(const path& p, error_code& ec) noexcept; + //long long filesize(const nana::string& file); + + + bool create_directories(const path& p); + //bool create_directories(const path& p, error_code& ec) noexcept; + bool create_directory(const path& p); + //bool create_directory(const path& p, error_code& ec) noexcept; + bool create_directory(const path& p, const path& attributes); + //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; + bool create_directory(const nana::string& dir, bool & if_exist); + bool create_directory(const path& p, bool & if_exist) + { + return create_directory(p.name(), if_exist); + }; + + + bool modified_file_time(const nana::string& file, struct tm&); + + + nana::string path_user(); + + + path current_path(); + //path current_path(error_code& ec); + void current_path(const path& p); + //void current_path(const path& p, error_code& ec) noexcept; + //nana::string path_current(); + + + //bool remove(const path& p); + //bool remove(const path& p, error_code& ec) noexcept; + bool rmfile(const nana::char_t* file); + + //uintmax_t remove_all(const path& p); + //uintmax_t remove_all(const path& p, error_code& ec) noexcept; + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty); + nana::string root(const nana::string& path); + + }//end namespace filesystem }//end namespace nana diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index e79f786a..f578afeb 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -134,7 +134,7 @@ namespace filesystem for(auto & f : files) { - if(f.directory) + if(f.attr.directory) rm_dir_recursive(path + f.path().name()); else rmfile((path + f.path().name()).c_str()); @@ -196,8 +196,8 @@ namespace filesystem LARGE_INTEGER li; li.u.LowPart = fad.nFileSizeLow; li.u.HighPart = fad.nFileSizeHigh; - attr.bytes = li.QuadPart; - attr.is_directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + attr.size = li.QuadPart; + attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); return true; } @@ -214,7 +214,7 @@ namespace filesystem return false; } - long long filesize(const nana::string& file) + uintmax_t file_size(const nana::string& file) { #if defined(NANA_WINDOWS) //Some compilation environment may fail to link to GetFileSizeEx @@ -281,7 +281,7 @@ namespace filesystem return false; } - bool mkdir(const nana::string& path, bool & if_exist) + bool create_directory(const nana::string& path, bool & if_exist) { if_exist = false; if(path.size() == 0) return false; @@ -414,7 +414,7 @@ namespace filesystem return nana::string(); } - nana::string path_current() + path current_path() { #if defined(NANA_WINDOWS) nana::char_t buf[MAX_PATH]; From f55c54f7b4ae04336f6154d67f2ec0f2156e4e1e Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:21:01 +0200 Subject: [PATCH 20/49] filesystem to experimental to avoid conflicts with fs_utillity --- include/nana/filesystem/filesystem.hpp | 5 +- source/filesystem/filesystem.cpp | 724 +++++++++++++------------ 2 files changed, 366 insertions(+), 363 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 3b8f3dd7..c117a797 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -46,7 +46,7 @@ // namespace std { namespace experimental { namespace filesystem { inline namespace v1 { -namespace nana +namespace nana { namespace experimental { namespace filesystem { @@ -73,7 +73,7 @@ namespace filesystem //enum class directory_options; // class filesystem_error; - enum class error { none = 0 }; + enum class error { none = 0 }; // deprecate ?? struct attribute // deprecate ?? { @@ -449,6 +449,7 @@ namespace filesystem }//end namespace filesystem +} //end namespace experimental }//end namespace nana #endif diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index f578afeb..07d297f3 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -36,407 +36,409 @@ #include #endif -namespace nana -{ -namespace filesystem -{ -//Because of No wide character version of POSIX +namespace nana { + namespace experimental + { + namespace filesystem + { + //Because of No wide character version of POSIX #if defined(NANA_LINUX) - typedef std::string string_t; - const char* splstr = "/\\"; + typedef std::string string_t; + const char* splstr = "/\\"; #else - typedef nana::string string_t; - const nana::char_t* splstr = STR("/\\"); + typedef nana::string string_t; + const nana::char_t* splstr = STR("/\\"); #endif - //class path - path::path(){} + //class path + path::path() {} - path::path(const nana::string& text) + path::path(const nana::string& text) #if defined(NANA_WINDOWS) - :text_(text) - { + : text_(text) + { #else - :text_(nana::charset(text)) - { + :text_(nana::charset(text)) + { #endif - auto pos = text_.find_last_of(splstr); - for(; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) - text_.erase(pos); - } + auto pos = text_.find_last_of(splstr); + for (; (pos != string_t::npos) && (pos + 1 == text_.size()); pos = text_.find_last_of(splstr)) + text_.erase(pos); + } - bool path::empty() const - { + bool path::empty() const + { #if defined(NANA_WINDOWS) - return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); + return (::GetFileAttributes(text_.c_str()) == INVALID_FILE_ATTRIBUTES); #elif defined(NANA_LINUX) - struct stat sta; - return (::stat(text_.c_str(), &sta) == -1); + struct stat sta; + return (::stat(text_.c_str(), &sta) == -1); #endif - } + } - path path::root() const - { - #if defined(NANA_WINDOWS) - return path(filesystem::root(text_)); - #elif defined(NANA_LINUX) - return path(filesystem::root(nana::charset(text_))); - #endif - } - - file_type path::what() const - { + path path::root() const + { #if defined(NANA_WINDOWS) - unsigned long attr = ::GetFileAttributes(text_.c_str()); - if(INVALID_FILE_ATTRIBUTES == attr) - return file_type:: not_found ; //?? - - if(FILE_ATTRIBUTE_DIRECTORY & attr) - return file_type::directory; - - return file_type::regular; + return path(filesystem::root(text_)); #elif defined(NANA_LINUX) - struct stat sta; - if(-1 == ::stat(text_.c_str(), &sta)) - return file_type:: not_found ; //?? + return path(filesystem::root(nana::charset(text_))); +#endif + } - if((S_IFDIR & sta.st_mode) == S_IFDIR) - return file_type::directory; + file_type path::what() const + { +#if defined(NANA_WINDOWS) + unsigned long attr = ::GetFileAttributes(text_.c_str()); + if (INVALID_FILE_ATTRIBUTES == attr) + return file_type::not_found; //?? + + if (FILE_ATTRIBUTE_DIRECTORY & attr) + return file_type::directory; - if((S_IFREG & sta.st_mode) == S_IFREG) return file_type::regular; +#elif defined(NANA_LINUX) + struct stat sta; + if (-1 == ::stat(text_.c_str(), &sta)) + return file_type::not_found; //?? - return file_type::none; + if ((S_IFDIR & sta.st_mode) == S_IFDIR) + return file_type::directory; + + if ((S_IFREG & sta.st_mode) == S_IFREG) + return file_type::regular; + + return file_type::none; #endif - } + } - nana::string path::name() const - { - string_t::size_type pos = text_.find_last_of(splstr); + nana::string path::name() const + { + string_t::size_type pos = text_.find_last_of(splstr); #if defined(NANA_WINDOWS) - return text_.substr(pos + 1); + return text_.substr(pos + 1); #else - return nana::charset(text_.substr(pos + 1)); -#endif - } - //end class path - - namespace detail - { - //rm_dir_recursive - //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories - bool rm_dir_recursive(nana::string&& dir) - { - std::vector files; - nana::string path = dir; - path += '\\'; - - std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); - - for(auto & f : files) - { - if(f.attr.directory) - rm_dir_recursive(path + f.path().name()); - else - rmfile((path + f.path().name()).c_str()); - } - - return rmdir(dir.c_str(), true); - } - - bool mkdir_helper(const nana::string& dir, bool & if_exist) - { -#if defined(NANA_WINDOWS) - if(::CreateDirectory(dir.c_str(), 0)) - { - if_exist = false; - return true; - } - - if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); -#elif defined(NANA_LINUX) - if(0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) - { - if_exist = false; - return true; - } - - if_exist = (errno == EEXIST); -#endif - return false; - } - -#if defined(NANA_WINDOWS) - void filetime_to_c_tm(FILETIME& ft, struct tm& t) - { - FILETIME local_file_time; - if(::FileTimeToLocalFileTime(&ft, &local_file_time)) - { - SYSTEMTIME st; - ::FileTimeToSystemTime(&local_file_time, &st); - t.tm_year = st.wYear - 1900; - t.tm_mon = st.wMonth - 1; - t.tm_mday = st.wDay; - t.tm_wday = st.wDayOfWeek - 1; - t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); - - t.tm_hour = st.wHour; - t.tm_min = st.wMinute; - t.tm_sec = st.wSecond; - } - } -#endif - }//end namespace detail - - bool file_attrib(const nana::string& file, attribute& attr) - { -#if defined(NANA_WINDOWS) - WIN32_FILE_ATTRIBUTE_DATA fad; - if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) - { - LARGE_INTEGER li; - li.u.LowPart = fad.nFileSizeLow; - li.u.HighPart = fad.nFileSizeHigh; - attr.size = li.QuadPart; - attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); - detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); - return true; - } -#elif defined(NANA_LINUX) - struct stat fst; - if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) - { - attr.bytes = fst.st_size; - attr.is_directory = (0 != (040000 & fst.st_mode)); - attr.modified = *(::localtime(&fst.st_ctime)); - return true; - } -#endif - return false; - } - - uintmax_t file_size(const nana::string& file) - { -#if defined(NANA_WINDOWS) - //Some compilation environment may fail to link to GetFileSizeEx - typedef BOOL (__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); - GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); - if(get_file_size_ex) - { - HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if(INVALID_HANDLE_VALUE != handle) - { - LARGE_INTEGER li; - if(!get_file_size_ex(handle, &li)) - li.QuadPart = 0; - - ::CloseHandle(handle); - return li.QuadPart; - } - } - return 0; -#elif defined(NANA_LINUX) - FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); - long long size = 0; - if(stream) - { - fseeko64(stream, 0, SEEK_END); - size = ftello64(stream); - fclose(stream); - } - return size; -#endif - } - - bool modified_file_time(const nana::string& file, struct tm& t) - { -#if defined(NANA_WINDOWS) - WIN32_FILE_ATTRIBUTE_DATA attr; - if(::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) - { - FILETIME local_file_time; - if(::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) - { - SYSTEMTIME st; - ::FileTimeToSystemTime(&local_file_time, &st); - t.tm_year = st.wYear - 1900; - t.tm_mon = st.wMonth - 1; - t.tm_mday = st.wDay; - t.tm_wday = st.wDayOfWeek - 1; - t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); - - t.tm_hour = st.wHour; - t.tm_min = st.wMinute; - t.tm_sec = st.wSecond; - return true; - } - } -#elif defined(NANA_LINUX) - struct stat attr; - if(0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) - { - t = *(::localtime(&attr.st_ctime)); - return true; - } -#endif - return false; - } - - bool create_directory(const nana::string& path, bool & if_exist) - { - if_exist = false; - if(path.size() == 0) return false; - - nana::string root; -#if defined(NANA_WINDOWS) - if(path.size() > 3 && path[1] == STR(':')) - root = path.substr(0, 3); -#elif defined(NANA_LINUX) - if(path[0] == STR('/')) - root = '/'; -#endif - bool mkstat = false; - std::size_t beg = root.size(); - - while(true) - { - beg = path.find_first_not_of(STR("/\\"), beg); - if(beg == path.npos) - break; - - std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); - if(pos != path.npos) - { - root += path.substr(beg, pos - beg); - - mkstat = detail::mkdir_helper(root, if_exist); - if(mkstat == false && if_exist == false) - return false; - -#if defined(NANA_WINDOWS) - root += STR('\\'); -#elif defined(NANA_LINUX) - root += STR('/'); + return nana::charset(text_.substr(pos + 1)); #endif } - else + //end class path + + namespace detail { - if(beg + 1 < path.size()) + //rm_dir_recursive + //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories + bool rm_dir_recursive(nana::string&& dir) { - root += path.substr(beg); - mkstat = detail::mkdir_helper(root, if_exist); + std::vector files; + nana::string path = dir; + path += '\\'; + + std::copy(directory_iterator(dir), directory_iterator(), std::back_inserter(files)); + + for (auto & f : files) + { + if (f.attr.directory) + rm_dir_recursive(path + f.path().name()); + else + rmfile((path + f.path().name()).c_str()); + } + + return rmdir(dir.c_str(), true); } - break; - } - beg = pos + 1; - } - return mkstat; - } - bool rmfile(const nana::char_t* file) - { + bool mkdir_helper(const nana::string& dir, bool & if_exist) + { #if defined(NANA_WINDOWS) - bool ret = false; - if(file) - { - ret = (::DeleteFile(file) == TRUE); - if(!ret) - ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); - } + if (::CreateDirectory(dir.c_str(), 0)) + { + if_exist = false; + return true; + } - return ret; + if_exist = (::GetLastError() == ERROR_ALREADY_EXISTS); #elif defined(NANA_LINUX) - if(std::remove(static_cast(nana::charset(file)).c_str())) - return (errno == ENOENT); - return true; -#endif - } + if (0 == ::mkdir(static_cast(nana::charset(dir)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) + { + if_exist = false; + return true; + } + + if_exist = (errno == EEXIST); +#endif + return false; + } - bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) - { - bool ret = false; - if(dir) - { #if defined(NANA_WINDOWS) - ret = (::RemoveDirectory(dir) == TRUE); - if(!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) - ret = detail::rm_dir_recursive(dir); -#elif defined(NANA_LINUX) - std::string mbstr = nana::charset(dir); - if(::rmdir(mbstr.c_str())) - { - if(!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) - ret = detail::rm_dir_recursive(dir); - } - else - ret = true; + void filetime_to_c_tm(FILETIME& ft, struct tm& t) + { + FILETIME local_file_time; + if (::FileTimeToLocalFileTime(&ft, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + } + } #endif - } - return ret; - } + }//end namespace detail - nana::string root(const nana::string& path) - { - std::size_t index = path.size(); - - if(index) - { - const nana::char_t * str = path.c_str(); - - for(--index; index > 0; --index) + bool file_attrib(const nana::string& file, attribute& attr) { - nana::char_t c = str[index]; - if(c != '\\' && c != '/') - break; - } - - for(--index; index > 0; --index) - { - nana::char_t c = str[index]; - if(c == '\\' || c == '/') - break; - } - } - - return index?path.substr(0, index + 1):nana::string(); - } - - nana::string path_user() - { #if defined(NANA_WINDOWS) - nana::char_t path[MAX_PATH]; - if(SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) - return path; + WIN32_FILE_ATTRIBUTE_DATA fad; + if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &fad)) + { + LARGE_INTEGER li; + li.u.LowPart = fad.nFileSizeLow; + li.u.HighPart = fad.nFileSizeHigh; + attr.size = li.QuadPart; + attr.directory = (0 != (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + detail::filetime_to_c_tm(fad.ftLastWriteTime, attr.modified); + return true; + } #elif defined(NANA_LINUX) - const char * s = ::getenv("HOME"); - if(s) - return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); + struct stat fst; + if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &fst)) + { + attr.bytes = fst.st_size; + attr.is_directory = (0 != (040000 & fst.st_mode)); + attr.modified = *(::localtime(&fst.st_ctime)); + return true; + } #endif - return nana::string(); - } - - path current_path() - { -#if defined(NANA_WINDOWS) - nana::char_t buf[MAX_PATH]; - DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); - if(len) - { - if(len > MAX_PATH) - { - nana::char_t * p = new nana::char_t[len + 1]; - ::GetCurrentDirectory(len + 1, p); - nana::string s = p; - delete [] p; - return s; + return false; } - return buf; - } + + uintmax_t file_size(const nana::string& file) + { +#if defined(NANA_WINDOWS) + //Some compilation environment may fail to link to GetFileSizeEx + typedef BOOL(__stdcall *GetFileSizeEx_fptr_t)(HANDLE, PLARGE_INTEGER); + GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); + if (get_file_size_ex) + { + HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE != handle) + { + LARGE_INTEGER li; + if (!get_file_size_ex(handle, &li)) + li.QuadPart = 0; + + ::CloseHandle(handle); + return li.QuadPart; + } + } + return 0; #elif defined(NANA_LINUX) - const char * s = ::getenv("PWD"); - if(s) - return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); + FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); + long long size = 0; + if (stream) + { + fseeko64(stream, 0, SEEK_END); + size = ftello64(stream); + fclose(stream); + } + return size; #endif - return nana::string(); - } -}//end namespace filesystem + } + + bool modified_file_time(const nana::string& file, struct tm& t) + { +#if defined(NANA_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA attr; + if (::GetFileAttributesEx(file.c_str(), GetFileExInfoStandard, &attr)) + { + FILETIME local_file_time; + if (::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &local_file_time)) + { + SYSTEMTIME st; + ::FileTimeToSystemTime(&local_file_time, &st); + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; + t.tm_mday = st.wDay; + t.tm_wday = st.wDayOfWeek - 1; + t.tm_yday = nana::date::day_in_year(st.wYear, st.wMonth, st.wDay); + + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + return true; + } + } +#elif defined(NANA_LINUX) + struct stat attr; + if (0 == ::stat(static_cast(nana::charset(file)).c_str(), &attr)) + { + t = *(::localtime(&attr.st_ctime)); + return true; + } +#endif + return false; + } + + bool create_directory(const nana::string& path, bool & if_exist) + { + if_exist = false; + if (path.size() == 0) return false; + + nana::string root; +#if defined(NANA_WINDOWS) + if (path.size() > 3 && path[1] == STR(':')) + root = path.substr(0, 3); +#elif defined(NANA_LINUX) + if (path[0] == STR('/')) + root = '/'; +#endif + bool mkstat = false; + std::size_t beg = root.size(); + + while (true) + { + beg = path.find_first_not_of(STR("/\\"), beg); + if (beg == path.npos) + break; + + std::size_t pos = path.find_first_of(STR("/\\"), beg + 1); + if (pos != path.npos) + { + root += path.substr(beg, pos - beg); + + mkstat = detail::mkdir_helper(root, if_exist); + if (mkstat == false && if_exist == false) + return false; + +#if defined(NANA_WINDOWS) + root += STR('\\'); +#elif defined(NANA_LINUX) + root += STR('/'); +#endif + } + else + { + if (beg + 1 < path.size()) + { + root += path.substr(beg); + mkstat = detail::mkdir_helper(root, if_exist); + } + break; + } + beg = pos + 1; + } + return mkstat; + } + + bool rmfile(const nana::char_t* file) + { +#if defined(NANA_WINDOWS) + bool ret = false; + if (file) + { + ret = (::DeleteFile(file) == TRUE); + if (!ret) + ret = (ERROR_FILE_NOT_FOUND == ::GetLastError()); + } + + return ret; +#elif defined(NANA_LINUX) + if (std::remove(static_cast(nana::charset(file)).c_str())) + return (errno == ENOENT); + return true; +#endif + } + + bool rmdir(const nana::char_t* dir, bool fails_if_not_empty) + { + bool ret = false; + if (dir) + { +#if defined(NANA_WINDOWS) + ret = (::RemoveDirectory(dir) == TRUE); + if (!fails_if_not_empty && (::GetLastError() == ERROR_DIR_NOT_EMPTY)) + ret = detail::rm_dir_recursive(dir); +#elif defined(NANA_LINUX) + std::string mbstr = nana::charset(dir); + if (::rmdir(mbstr.c_str())) + { + if (!fails_if_not_empty && (errno == EEXIST || errno == ENOTEMPTY)) + ret = detail::rm_dir_recursive(dir); + } + else + ret = true; +#endif + } + return ret; + } + + nana::string root(const nana::string& path) + { + std::size_t index = path.size(); + + if (index) + { + const nana::char_t * str = path.c_str(); + + for (--index; index > 0; --index) + { + nana::char_t c = str[index]; + if (c != '\\' && c != '/') + break; + } + + for (--index; index > 0; --index) + { + nana::char_t c = str[index]; + if (c == '\\' || c == '/') + break; + } + } + + return index ? path.substr(0, index + 1) : nana::string(); + } + + nana::string path_user() + { +#if defined(NANA_WINDOWS) + nana::char_t path[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPath(0, CSIDL_PROFILE, 0, SHGFP_TYPE_CURRENT, path))) + return path; +#elif defined(NANA_LINUX) + const char * s = ::getenv("HOME"); + if (s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + + path current_path() + { +#if defined(NANA_WINDOWS) + nana::char_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectory(MAX_PATH, buf); + if (len) + { + if (len > MAX_PATH) + { + nana::char_t * p = new nana::char_t[len + 1]; + ::GetCurrentDirectory(len + 1, p); + nana::string s = p; + delete[] p; + return s; + } + return buf; + } +#elif defined(NANA_LINUX) + const char * s = ::getenv("PWD"); + if (s) + return nana::charset(std::string(s, std::strlen(s)), nana::unicode::utf8); +#endif + return nana::string(); + } + }//end namespace filesystem + } //end namespace experimental }//end namespace nana From 895dbcbe7db4f465b64ab9a40e3fbbd33be2aabd Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:26:42 +0200 Subject: [PATCH 21/49] FIX: compiling with VC2015 RC --- include/nana/config.hpp | 14 +++++++++++++- source/gui/widgets/combox.cpp | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 77b9005c..fecf633f 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -13,6 +13,18 @@ #ifndef NANA_CONFIG_HPP #define NANA_CONFIG_HPP + +#if defined(_MSC_VER) +#if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. +#define STD_CODECVT_NOT_SUPPORTED +#endif // _MSC_VER == 1900 +#endif // _MSVC + //Select platform automatically #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) //Windows: @@ -35,7 +47,7 @@ #define PLATFORM_SPEC_HPP #define STD_CODECVT_NOT_SUPPORTED #else -# static_assert(false, "Only Windows and Unix are support now"); +# static_assert(false, "Only Windows and Unix are supported now"); #endif #if defined(NANA_MINGW) || defined(NANA_LINUX) diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index b1d401f5..64208c54 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace nana { arg_combox::arg_combox(combox& wdg): widget(wdg) From e99783ed54d1eb2ebe76bf6497d92a25ffd6df4c Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 23:55:19 +0200 Subject: [PATCH 22/49] FIX: inline functions and one default constructor. Tested OK ! --- include/nana/filesystem/filesystem.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index c117a797..60a0ea12 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -139,6 +139,7 @@ namespace filesystem file_type what() const; nana::string name() const; + operator nana::string() { return name(); } private: #if defined(NANA_WINDOWS) nana::string text_; @@ -154,7 +155,7 @@ namespace filesystem attribute attr{}; //file_status m_status; - directory_entry(); + directory_entry(){} directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) :m_path{filename}, attr{size, is_directory} {} @@ -368,8 +369,8 @@ namespace filesystem }; // enable directory_iterator range-based for statements - directory_iterator begin(directory_iterator iter) noexcept { return iter; } - directory_iterator end(const directory_iterator&) noexcept { return {}; } + inline directory_iterator begin(directory_iterator iter) noexcept { return iter; } + inline directory_iterator end(const directory_iterator&) noexcept { return {}; } //class recursive_directory_iterator; //// enable recursive_directory_iterator range-based for statements @@ -392,13 +393,13 @@ namespace filesystem // file_status status(const path& p); bool file_attrib(const nana::string& file, attribute&); - bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + inline bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; - bool is_empty(const path& p) + inline bool is_empty(const path& p) { directory_iterator d(p) ; return d->attr.directory ? d == directory_iterator() @@ -407,7 +408,7 @@ namespace filesystem //bool is_empty(const path& p, error_code& ec) noexcept; uintmax_t file_size(const nana::string& file); // deprecate? - uintmax_t file_size(const path& p){return file_size(p.name());} + inline uintmax_t file_size(const path& p){return file_size(p.name());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); @@ -419,7 +420,7 @@ namespace filesystem bool create_directory(const path& p, const path& attributes); //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; bool create_directory(const nana::string& dir, bool & if_exist); - bool create_directory(const path& p, bool & if_exist) + inline bool create_directory(const path& p, bool & if_exist) { return create_directory(p.name(), if_exist); }; From 888e65aa842acdf20aca08f4a666eb03913961f7 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 00:46:59 +0200 Subject: [PATCH 23/49] the linker don't like my inlines --- include/nana/filesystem/filesystem.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 60a0ea12..35de2a94 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -9,7 +9,10 @@ * @file: stdex/filesystem/filesystem.hpp * @description: * file_iterator is a toolkit for applying each file and directory in a - * specified path. + * specified path. + * Modiffied by Ariel Vina-Rodriguez: + * Now mimic std::experimental::filesystem::v1 (boost v3) + * and need VC2015 or a C++11 compiler. With a few correction will be compiler by VC2013 */ // http://en.cppreference.com/w/cpp/experimental/fs @@ -207,6 +210,12 @@ namespace filesystem if(end_ && (end_ == x.end_)) return true; return (value_.path().name() == x.value_.path().name()); } + + + // enable directory_iterator range-based for statements + directory_iterator begin( ) noexcept { return *this; } + directory_iterator end( ) noexcept { return {}; } + private: template static bool _m_ignore(const Char * p) @@ -368,9 +377,6 @@ namespace filesystem value_type value_; }; - // enable directory_iterator range-based for statements - inline directory_iterator begin(directory_iterator iter) noexcept { return iter; } - inline directory_iterator end(const directory_iterator&) noexcept { return {}; } //class recursive_directory_iterator; //// enable recursive_directory_iterator range-based for statements @@ -407,7 +413,7 @@ namespace filesystem } //bool is_empty(const path& p, error_code& ec) noexcept; - uintmax_t file_size(const nana::string& file); // deprecate? + uintmax_t file_size(const nana::string& file); // deprecate? inline uintmax_t file_size(const path& p){return file_size(p.name());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); From a42931830f05d7239a39071d7aa7152e2cf60cdb Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 02:00:06 +0200 Subject: [PATCH 24/49] mimic path.filename() --- include/nana/filesystem/filesystem.hpp | 22 +++++++++++----------- source/filesystem/filesystem.cpp | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 35de2a94..790968ca 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -141,8 +141,8 @@ namespace filesystem path root() const; file_type what() const; - nana::string name() const; - operator nana::string() { return name(); } + nana::string filename() const; + operator nana::string() { return filename(); } private: #if defined(NANA_WINDOWS) nana::string text_; @@ -159,8 +159,8 @@ namespace filesystem //file_status m_status; directory_entry(){} - directory_entry(const nana::string& filename, bool is_directory, uintmax_t size) - :m_path{filename}, attr{size, is_directory} + directory_entry(const nana::string& filename_, bool is_directory, uintmax_t size) + :m_path{filename_}, attr{size, is_directory} {} void assign (const path& p){ m_path=p;} @@ -187,7 +187,7 @@ namespace filesystem directory_iterator():end_(true), handle_(nullptr){} directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } - directory_iterator(const path& file_path) { _m_prepare(file_path.name()); } + directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } const value_type& operator*() const { return value_; } @@ -208,7 +208,7 @@ namespace filesystem bool equal(const directory_iterator& x) const { if(end_ && (end_ == x.end_)) return true; - return (value_.path().name() == x.value_.path().name()); + return (value_.path().filename() == x.value_.path().filename()); } @@ -284,7 +284,7 @@ namespace filesystem } else { - value_.name = nana::charset(dnt->d_name); + value_.m_path = nana::charset(dnt->d_name); value_.size = 0; value_.directory = false; } @@ -339,7 +339,7 @@ namespace filesystem (FILE_ATTRIBUTE_DIRECTORY & wfd_.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY, wfd_.nFileSizeLow); else - value_.name = nana::charset(dnt->d_name); + value_.m_path = nana::charset(dnt->d_name); } else end_ = true; @@ -400,7 +400,7 @@ namespace filesystem bool file_attrib(const nana::string& file, attribute&); inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - inline bool is_directory(const path& p){return directory_iterator(p.name())->attr.directory; } + inline bool is_directory(const path& p){return directory_iterator(p.filename())->attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; @@ -414,7 +414,7 @@ namespace filesystem //bool is_empty(const path& p, error_code& ec) noexcept; uintmax_t file_size(const nana::string& file); // deprecate? - inline uintmax_t file_size(const path& p){return file_size(p.name());} + inline uintmax_t file_size(const path& p){return file_size(p.filename());} //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); @@ -428,7 +428,7 @@ namespace filesystem bool create_directory(const nana::string& dir, bool & if_exist); inline bool create_directory(const path& p, bool & if_exist) { - return create_directory(p.name(), if_exist); + return create_directory(p.filename(), if_exist); }; diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 07d297f3..4c6e8d22 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -110,7 +110,7 @@ namespace nana { #endif } - nana::string path::name() const + nana::string path::filename() const { string_t::size_type pos = text_.find_last_of(splstr); #if defined(NANA_WINDOWS) @@ -136,9 +136,9 @@ namespace nana { for (auto & f : files) { if (f.attr.directory) - rm_dir_recursive(path + f.path().name()); + rm_dir_recursive(path + f.path().filename()); else - rmfile((path + f.path().name()).c_str()); + rmfile((path + f.path().filename()).c_str()); } return rmdir(dir.c_str(), true); From 9fbabadd7828316b70126f68e045bc3b0835ee68 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sun, 24 May 2015 03:12:02 +0200 Subject: [PATCH 25/49] better mimic? --- include/nana/filesystem/filesystem.hpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 790968ca..658579fd 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -142,11 +142,17 @@ namespace filesystem file_type what() const; nana::string filename() const; - operator nana::string() { return filename(); } - private: #if defined(NANA_WINDOWS) + public: + nana::string to_string() const { return text_; } + operator nana::string() const { return text_; } + private: nana::string text_; #else + public: + std::string to_string() const { return text_; } + operator std::string() const { return text_; } + private: std::string text_; #endif }; @@ -187,7 +193,7 @@ namespace filesystem directory_iterator():end_(true), handle_(nullptr){} directory_iterator(const nana::string& file_path) { _m_prepare(file_path); } - directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } + //directory_iterator(const path& file_path) { _m_prepare(file_path.filename()); } const value_type& operator*() const { return value_; } @@ -400,7 +406,8 @@ namespace filesystem bool file_attrib(const nana::string& file, attribute&); inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} - inline bool is_directory(const path& p){return directory_iterator(p.filename())->attr.directory; } + inline bool is_directory(const path& p) { return directory_iterator{ p }->attr.directory; }//works?? + inline bool is_directory(const directory_entry& d) { return d.attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; //bool is_regular_file(file_status s) noexcept; From ae1d01814a2134d2e3302516204ee02f13c87586 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 22 May 2015 23:29:48 +0200 Subject: [PATCH 26/49] FIX: linker warning which eventually produce errors --- build/vc2013/nana.vcxproj | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index 7e216758..ea824f68 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -70,21 +70,29 @@ ../bin/vc2013/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); ../bin/vc2013/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ../bin/vc2013/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); ../bin/vc2013/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ @@ -102,7 +110,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -119,7 +127,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -141,7 +149,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) @@ -162,7 +170,7 @@ true - $(OutDir)\nana_$(ConfigurationName)_$(PlatformShortName).lib + $(TargetPath) From b37ecda1877583fa922b798ba3b99e1df8bb9e7d Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 00:32:30 +0200 Subject: [PATCH 27/49] fix more warning --- build/vc2013/nana.vcxproj | 16 ++++++++-------- include/nana/config.hpp | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build/vc2013/nana.vcxproj b/build/vc2013/nana.vcxproj index ea824f68..03fe61cb 100644 --- a/build/vc2013/nana.vcxproj +++ b/build/vc2013/nana.vcxproj @@ -67,32 +67,32 @@ - ../bin/vc2013/ + ../bin/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ + ../bin/ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ - ../bin/vc2013/ + ../bin/ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ ..\..\include;$(IncludePath) ..\..\source;$(VC_SourcePath); - ../bin/vc2013/ + ../bin/ $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) - ..\..\..\temp\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 77b9005c..30ae2dc5 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -13,6 +13,21 @@ #ifndef NANA_CONFIG_HPP #define NANA_CONFIG_HPP + +#if defined(_MSC_VER) + #define _SCL_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_DEPRECATE + #pragma warning(disable : 4996) + #if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. + #define STD_CODECVT_NOT_SUPPORTED + #endif // _MSC_VER == 1900 +#endif // _MSVC + //Select platform automatically #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) //Windows: @@ -35,7 +50,7 @@ #define PLATFORM_SPEC_HPP #define STD_CODECVT_NOT_SUPPORTED #else -# static_assert(false, "Only Windows and Unix are support now"); +# static_assert(false, "Only Windows and Unix are supported now"); #endif #if defined(NANA_MINGW) || defined(NANA_LINUX) From 80aed9c94baa086fd8cea0579820325cd4c13c49 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 01:49:40 +0200 Subject: [PATCH 28/49] nana filesystem need vc2015 --- build/vc2013/nana.vcxproj.filters | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/vc2013/nana.vcxproj.filters b/build/vc2013/nana.vcxproj.filters index f0f82981..1b098164 100644 --- a/build/vc2013/nana.vcxproj.filters +++ b/build/vc2013/nana.vcxproj.filters @@ -301,4 +301,9 @@ Source Files\nana\gui\widgets + + + Header Files + + \ No newline at end of file From b1db4b2e1467d7617641150a6d5dff246f409f91 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Sat, 23 May 2015 02:13:42 +0200 Subject: [PATCH 29/49] project for VS2015 --- build/vc2015/nana.sln | 28 +++ build/vc2015/nana.vcxproj | 266 +++++++++++++++++++++++++ build/vc2015/nana.vcxproj.filters | 312 ++++++++++++++++++++++++++++++ 3 files changed, 606 insertions(+) create mode 100644 build/vc2015/nana.sln create mode 100644 build/vc2015/nana.vcxproj create mode 100644 build/vc2015/nana.vcxproj.filters diff --git a/build/vc2015/nana.sln b/build/vc2015/nana.sln new file mode 100644 index 00000000..eab31ab5 --- /dev/null +++ b/build/vc2015/nana.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{25B21068-491B-4A9F-B99F-6C27BF31BAAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.ActiveCfg = Debug|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x64.Build.0 = Debug|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x86.ActiveCfg = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Debug|x86.Build.0 = Debug|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.ActiveCfg = Release|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x64.Build.0 = Release|x64 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.ActiveCfg = Release|Win32 + {25B21068-491B-4A9F-B99F-6C27BF31BAAD}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vc2015/nana.vcxproj b/build/vc2015/nana.vcxproj new file mode 100644 index 00000000..94b72562 --- /dev/null +++ b/build/vc2015/nana.vcxproj @@ -0,0 +1,266 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {25B21068-491B-4A9F-B99F-6C27BF31BAAD} + Win32Proj + nana + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + ../bin/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ../bin/ + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + ..\..\include;$(IncludePath) + ..\..\source;$(VC_SourcePath); + ../bin/ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + false + + + Windows + true + + + $(TargetPath) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + $(TargetPath) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + + + Windows + true + true + true + + + $(TargetPath) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + + + $(TargetPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vc2015/nana.vcxproj.filters b/build/vc2015/nana.vcxproj.filters new file mode 100644 index 00000000..cb51dab8 --- /dev/null +++ b/build/vc2015/nana.vcxproj.filters @@ -0,0 +1,312 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b0bd11b1-bcbb-4e05-885e-44295bc1a7bb} + + + {aab16aa3-c8d4-4495-8606-1b21ae739ee5} + + + {c395f107-7102-415b-a019-54e7cf3575af} + + + {e2569be2-9e68-477d-8b59-e248595de6c7} + + + {52ed7f8e-fa48-495e-af1f-4df013205a35} + + + {87d14798-9015-4162-b9ab-72c741cff063} + + + {4f8e7d23-9fe1-4409-bb03-2bd0809e606b} + + + {85c9c1bb-d87b-4481-bf3c-7425f680a12d} + + + {8058b530-86ec-4d72-890d-345aa30db056} + + + {87b124cb-408d-460b-a81b-8a788bbae0d9} + + + {b10db2f1-0542-421a-9e1d-4357e3be5f68} + + + {59f186c8-f5f8-4499-8e19-f278d4754220} + + + {5acf1733-47b2-4872-a105-66c7ad15cd39} + + + {a81fa10e-1274-44e0-92a0-434fa28f89ae} + + + {e95b4a72-643f-4416-af95-b0bbaf7f0c57} + + + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio\detail + + + Source Files\nana\audio + + + Source Files\nana\detail\win32 + + + Source Files\nana\filesystem + + + Source Files\nana\filesystem + + + Source Files\nana\gui\detail\win32 + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\widgets\skeletons + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui\widgets + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana\paint\detail + + + Source Files\nana\paint\detail + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\paint + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\system + + + Source Files\nana\threads + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui + + + Source Files\nana + + + Source Files\nana\gui\detail + + + Source Files\nana\gui + + + Source Files\nana\gui\widgets + + + Source Files\nana\filesystem + + + + + Header Files + + + \ No newline at end of file From 42819c64c21dd164b564093237f9f519be7dc228 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Thu, 28 May 2015 16:43:14 +0200 Subject: [PATCH 30/49] eliminate noexept from our filesystem because a compiler without filesystem is not C++11 complete anyway We will go with noexeot when we will have std::filesystem... --- include/nana/config.hpp | 23 +++++++++++++-------- include/nana/filesystem/filesystem.hpp | 28 +++++++++++++------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/include/nana/config.hpp b/include/nana/config.hpp index fecf633f..58d1ffad 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -15,14 +15,21 @@ #if defined(_MSC_VER) -#if (_MSC_VER == 1900) - // google: break any code that tries to use codecvt or codecvt. - // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. - // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. - // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. - // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. -#define STD_CODECVT_NOT_SUPPORTED -#endif // _MSC_VER == 1900 + #define _SCL_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_DEPRECATE + #pragma warning(disable : 4996) + #if (_MSC_VER < 1900) + // is this a good idea? + #define NOT_IMPLEMENTED_KEYWORD_noexcept + #endif // _MSC_VER < 1900 + #if (_MSC_VER == 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. + #define STD_CODECVT_NOT_SUPPORTED + #endif // _MSC_VER == 1900 #endif // _MSVC //Select platform automatically diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 658579fd..b00760d2 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -102,26 +102,26 @@ namespace filesystem perms m_prms = perms::unknown; public: - explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) :m_ft{ft}, m_prms{prms} {} - file_status(const file_status& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; - file_status(file_status&& fs) noexcept: m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(const file_status& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + file_status(file_status&& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; ~file_status(){}; - file_status& operator=(const file_status&) noexcept = default; - file_status& operator=(file_status&&fs) noexcept // = default; + file_status& operator=(const file_status&) = default; + file_status& operator=(file_status&&fs) // = default; { m_ft=fs.m_ft; m_prms = fs.m_prms; return *this; } // observers - file_type type() const noexcept{ return m_ft;} - perms permissions() const noexcept{ return m_prms;} + file_type type() const { return m_ft;} + perms permissions() const { return m_prms;} // modifiers - void type (file_type ft) noexcept { m_ft=ft ;} - void permissions(perms prms) noexcept { m_prms = prms; } + void type (file_type ft) { m_ft=ft ;} + void permissions(perms prms) { m_prms = prms; } }; /// concerned only with lexical and syntactic aspects and does not necessarily exist in @@ -174,8 +174,8 @@ namespace filesystem //file_status status() const; - operator const path&() const noexcept{return m_path;}; - const path& path() const noexcept{return m_path;} + operator const path&() const {return m_path;}; + const path& path() const {return m_path;} }; @@ -219,8 +219,8 @@ namespace filesystem // enable directory_iterator range-based for statements - directory_iterator begin( ) noexcept { return *this; } - directory_iterator end( ) noexcept { return {}; } + directory_iterator begin( ) { return *this; } + directory_iterator end( ) { return {}; } private: template @@ -405,7 +405,7 @@ namespace filesystem // file_status status(const path& p); bool file_attrib(const nana::string& file, attribute&); - inline bool is_directory(file_status s) noexcept{ return s.type() == file_type::directory ;} + inline bool is_directory(file_status s) { return s.type() == file_type::directory ;} inline bool is_directory(const path& p) { return directory_iterator{ p }->attr.directory; }//works?? inline bool is_directory(const directory_entry& d) { return d.attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; From 11d65763ce56d6b78b702ff419275e109a4e3622 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 29 May 2015 00:09:47 +0800 Subject: [PATCH 31/49] fix a crash when the size of a label is empty and '\t' is contained --- source/gui/detail/window_layout.cpp | 3 +++ source/paint/detail/native_paint_interface.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 99ab04ab..a77eff5f 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -24,6 +24,9 @@ namespace nana //class window_layout void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed) { + if (wd->drawer.graphics.empty()) + return; + if (nullptr == wd->effect.bground) { if (is_redraw) diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 7c96f7b6..584ff3dc 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -156,6 +156,9 @@ namespace detail nana::size text_extent_size(drawable_type dw, const nana::char_t * text, std::size_t len) { + if (nullptr == dw || nullptr == text || 0 == len) + return{}; + nana::size extents = raw_text_extent_size(dw, text, len); const nana::char_t* const end = text + len; From 3157f5f0569de78d62b8a02d8624f51a9def7315 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Fri, 29 May 2015 15:37:11 +0200 Subject: [PATCH 32/49] progressbar with stop() --- include/nana/gui/widgets/progress.hpp | 5 +++++ source/gui/widgets/progress.cpp | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/nana/gui/widgets/progress.hpp b/include/nana/gui/widgets/progress.hpp index 91e58ab7..f7697d7e 100644 --- a/include/nana/gui/widgets/progress.hpp +++ b/include/nana/gui/widgets/progress.hpp @@ -30,6 +30,8 @@ namespace nana unsigned Max(unsigned); void unknown(bool); bool unknown() const; + bool stop(bool s = true); + bool stoped() const; private: void attached(widget_reference, graph_reference) override; void refresh(graph_reference) override; @@ -45,6 +47,7 @@ namespace nana nana::paint::graphics* graph_{nullptr}; unsigned draw_width_{static_cast(-1)}; bool unknown_{false}; + bool stop_{false}; unsigned max_{100}; unsigned value_{0}; }; //end class drawer @@ -67,6 +70,8 @@ namespace nana unsigned amount(unsigned value); void unknown(bool); bool unknown() const; + bool stop(bool s=true); ///< request stop or cancel and return previus stop status + bool stoped() const; }; }//end namespace nana #endif diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 4459ddb1..e37b5814 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -89,6 +89,15 @@ namespace nana { return unknown_; } + bool trigger::stoped() const + { + return stop_; + } + bool trigger::stop(bool s) + { + std::swap(s,stop_); + return s; + } void trigger::refresh(graph_reference) { @@ -197,5 +206,13 @@ namespace nana { return get_drawer_trigger().unknown(); } + bool progress::stop(bool s) + { + return get_drawer_trigger().stop(s); + } + bool progress::stoped() const + { + return get_drawer_trigger().stoped(); + } //end class progress }//end namespace nana From ee9d102f8d7f3a4880af27f08c2fdae6aa977762 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 30 May 2015 16:55:03 +0800 Subject: [PATCH 33/49] refactor toolbar --- include/nana/gui/widgets/toolbar.hpp | 24 +- source/gui/widgets/toolbar.cpp | 366 ++++++++++++--------------- 2 files changed, 163 insertions(+), 227 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index efb8af74..0b097676 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -14,7 +14,6 @@ #define NANA_GUI_WIDGET_TOOLBAR_HPP #include "widget.hpp" -#include namespace nana { @@ -39,10 +38,10 @@ namespace nana basic_event selected; ///< A mouse click on a control button. basic_event enter; ///< The mouse enters a control button. basic_event leave; ///< The mouse leaves a control button. - }; struct item_type; + class item_container; class drawer : public drawer_trigger @@ -50,15 +49,12 @@ namespace nana struct drawer_impl_type; public: - typedef std::size_t size_type; + using size_type = std::size_t; drawer(); ~drawer(); - void append(const nana::string&, const nana::paint::image&); - void append(); - bool enable(size_type) const; - bool enable(size_type, bool); + item_container& items() const; void scale(unsigned); private: void refresh(graph_reference) override; @@ -69,32 +65,28 @@ namespace nana void mouse_down(graph_reference, const arg_mouse&) override; void mouse_up(graph_reference, const arg_mouse&) override; private: - size_type _m_which(int x, int y, bool want_if_disabled) const; - void _m_draw_background(const ::nana::color&); - void _m_draw(); - void _m_owner_sized(const arg_resized&); - private: - void _m_fill_pixels(item_type*, bool force); + size_type _m_which(point, bool want_if_disabled) const; + void _m_calc_pixels(item_type*, bool force); private: ::nana::toolbar* widget_; - ::nana::paint::graphics* graph_; drawer_impl_type* impl_; }; }//end namespace toolbar }//end namespace drawerbase + /// Control bar that contains buttons for controlling class toolbar : public widget_object { public: - typedef std::size_t size_type; ///< A type to count the number of elements. + using size_type = std::size_t; ///< A type to count the number of elements. toolbar() = default; toolbar(window, bool visible); toolbar(window, const rectangle& = rectangle(), bool visible = true); - void append(); ///< Adds a separator. + void separate(); ///< Adds a separator. void append(const nana::string& text, const nana::paint::image& img); ///< Adds a control button. void append(const nana::string& text); ///< Adds a control button. bool enable(size_type index) const; diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 3936cfce..b6aabc4d 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -11,10 +11,10 @@ */ #include -#include -#include #include +#include + namespace nana { arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn) @@ -25,13 +25,6 @@ namespace nana { namespace toolbar { - struct listitem - { - nana::string text; - nana::paint::image image; - bool enable; - }; - struct item_type { enum kind{ button, container}; @@ -43,28 +36,23 @@ namespace nana unsigned pixels{0}; nana::size textsize; bool enable{true}; - window other{nullptr}; kind type; - std::function answer; - std::vector children; item_type(const nana::string& text, const nana::paint::image& img, kind type) :text(text), image(img), type(type) {} }; - class container - { - container(const container&) = delete; - container& operator=(const container&) = delete; - public: - typedef std::vector::size_type size_type; - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - container() = default; - ~container() + + class item_container + { + public: + using container_type = std::vector; + using size_type = container_type::size_type; + + ~item_container() { for(auto ptr : cont_) delete ptr; @@ -98,7 +86,7 @@ namespace nana cont_.push_back(nullptr); } - void push_back() + void separate() { cont_.push_back(nullptr); } @@ -108,35 +96,17 @@ namespace nana return cont_.size(); } - item_type* at(size_type n) + container_type& container() { - if(n < cont_.size()) - return cont_[n]; - - throw std::out_of_range("toolbar: bad index!"); + return cont_; } - iterator begin() + item_type * at(size_type pos) { - return cont_.begin(); - } - - iterator end() - { - return cont_.end(); - } - - const_iterator begin() const - { - return cont_.cbegin(); - } - - const_iterator end() const - { - return cont_.cend(); + return cont_.at(pos); } private: - std::vector cont_; + container_type cont_; }; class item_renderer @@ -152,38 +122,35 @@ namespace nana void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state) { //draw background - if(state != state_t::normal) - graph.rectangle({ x, y, width, height }, false, { 0x33, 0x99, 0xFF }); - switch(state) + if (state != state_t::normal) { - case state_t::highlighted: - graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0xC0, 0xDD, 0xFC }, true); - break; - case state_t::selected: - graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0x99, 0xCC, 0xFF }, true); - default: break; + nana::rectangle background_r(x, y, width, height); + graph.rectangle(background_r, false, static_cast(0x3399FF)); + + if (state_t::highlighted == state || state_t::selected == state) + graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true); } - if(item.image.empty() == false) + if(!item.image.empty()) { - nana::size size = item.image.size(); - if(size.width > scale) size.width = scale; - if(size.height > scale) size.height = scale; + auto imgsize = item.image.size(); + if (imgsize.width > scale) imgsize.width = scale; + if (imgsize.height > scale) imgsize.height = scale; nana::point pos(x, y); - pos.x += static_cast(scale + extra_size - size.width) / 2; - pos.y += static_cast(height - size.height) / 2; + pos.x += static_cast(scale + extra_size - imgsize.width) / 2; + pos.y += static_cast(height - imgsize.height) / 2; - item.image.paste(size, graph, pos); + item.image.paste(imgsize, graph, pos); if(item.enable == false) { - nana::paint::graphics gh(size); - gh.bitblt(size, graph, pos); + nana::paint::graphics gh(imgsize); + gh.bitblt(imgsize, graph, pos); gh.rgb_to_wb(); gh.paste(graph, pos.x, pos.y); } else if(state == state_t::normal) - graph.blend(nana::rectangle(pos, size), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25); + graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25); x += scale; width -= scale; @@ -204,13 +171,15 @@ namespace nana struct drawer::drawer_impl_type { - event_handle event_size{nullptr}; + event_handle event_size{ nullptr }; + paint::graphics* graph_ptr{ nullptr }; + unsigned scale{16}; bool textout{false}; size_type which{npos}; item_renderer::state_t state{item_renderer::state_t::normal}; - container cont; + item_container items; ::nana::tooltip tooltip; }; @@ -225,116 +194,118 @@ namespace nana delete impl_; } - void drawer::append(const nana::string& text, const nana::paint::image& img) + item_container& drawer::items() const { - impl_->cont.push_back(text, img); - } - - void drawer::append() - { - impl_->cont.push_back(); - } - - bool drawer::enable(drawer::size_type n) const - { - if(impl_->cont.size() > n) - { - auto item = impl_->cont.at(n); - return (item && item->enable); - } - return false; - } - - bool drawer::enable(size_type n, bool eb) - { - if(impl_->cont.size() > n) - { - item_type * item = impl_->cont.at(n); - if(item && (item->enable != eb)) - { - item->enable = eb; - return true; - } - } - return false; + return impl_->items; } void drawer::scale(unsigned s) { impl_->scale = s; - for(auto m : impl_->cont) - _m_fill_pixels(m, true); + for(auto m : impl_->items.container()) + _m_calc_pixels(m, true); } - void drawer::refresh(graph_reference) + void drawer::refresh(graph_reference graph) { - _m_draw(); + int x = 2, y = 2; + + auto bgcolor = API::bgcolor(widget_->handle()); + graph.set_text_color(bgcolor); + graph.gradual_rectangle(graph.size(), bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.95), true); + + item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor); + size_type index = 0; + + for (auto item : impl_->items.container()) + { + if (item) + { + _m_calc_pixels(item, false); + ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal)); + x += item->pixels; + } + else + { + x += 2; + graph.line({ x, y + 2 }, { x, y + static_cast(impl_->scale + ir.extra_size) - 4 }, static_cast(0x808080)); + x += 4; + } + ++index; + } } void drawer::attached(widget_reference widget, graph_reference graph) { - graph_ = &graph; + impl_->graph_ptr = &graph; widget_ = static_cast< ::nana::toolbar*>(&widget); - widget.caption(STR("Nana Toolbar")); - impl_->event_size = widget.events().resized.connect_unignorable(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1)); + widget.caption(L"Nana Toolbar"); + impl_->event_size = API::events(widget.parent()).resized.connect_unignorable([this](const arg_resized& arg) + { + auto wd = widget_->handle(); + API::window_size(wd, nana::size(arg.width, widget_->size().height)); + API::update_window(wd); + }); } void drawer::detached() { API::umake_event(impl_->event_size); impl_->event_size = nullptr; + impl_->graph_ptr = nullptr; } void drawer::mouse_move(graph_reference graph, const arg_mouse& arg) { - if(arg.left_button == false) + if (arg.left_button) + return; + + size_type which = _m_which(arg.pos, true); + if(impl_->which != which) { - size_type which = _m_which(arg.pos.x, arg.pos.y, true); - if(impl_->which != which) + auto & container = impl_->items.container(); + if (impl_->which != npos && container.at(impl_->which)->enable) { - if (impl_->which != npos && impl_->cont.at(impl_->which)->enable) - { - ::nana::arg_toolbar arg{ *widget_, impl_->which }; - widget_->events().leave.emit(arg); - } - - impl_->which = which; - if(which == npos || impl_->cont.at(which)->enable) - { - impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted); - - _m_draw(); - API::lazy_refresh(); - - if (impl_->state == item_renderer::state_t::highlighted) - { - ::nana::arg_toolbar arg{ *widget_, which }; - widget_->events().enter.emit(arg); - } - } - - if(which != npos) - impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(impl_->cont.begin() + which))->text, 0); - else - impl_->tooltip.close(); + ::nana::arg_toolbar arg{ *widget_, impl_->which }; + widget_->events().leave.emit(arg); } + + impl_->which = which; + if (which == npos || container.at(which)->enable) + { + impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted); + + refresh(graph); + API::lazy_refresh(); + + if (impl_->state == item_renderer::state_t::highlighted) + { + ::nana::arg_toolbar arg{ *widget_, which }; + widget_->events().enter.emit(arg); + } + } + + if(which != npos) + impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(container.begin() + which))->text, 0); + else + impl_->tooltip.close(); } } - void drawer::mouse_leave(graph_reference, const arg_mouse&) + void drawer::mouse_leave(graph_reference graph, const arg_mouse&) { if(impl_->which != npos) { size_type which = impl_->which; impl_->which = npos; - _m_draw(); + refresh(graph); API::lazy_refresh(); - if (which != npos && impl_->cont.at(which)->enable) + if (which != npos && impl_->items.at(which)->enable) { ::nana::arg_toolbar arg{ *widget_, which }; widget_->events().leave.emit(arg); @@ -343,22 +314,22 @@ namespace nana impl_->tooltip.close(); } - void drawer::mouse_down(graph_reference, const arg_mouse&) + void drawer::mouse_down(graph_reference graph, const arg_mouse&) { impl_->tooltip.close(); - if(impl_->which != npos && (impl_->cont.at(impl_->which)->enable)) + if(impl_->which != npos && (impl_->items.at(impl_->which)->enable)) { impl_->state = item_renderer::state_t::selected; - _m_draw(); + refresh(graph); API::lazy_refresh(); } } - void drawer::mouse_up(graph_reference, const arg_mouse& arg) + void drawer::mouse_up(graph_reference graph, const arg_mouse& arg) { if(impl_->which != npos) { - size_type which = _m_which(arg.pos.x, arg.pos.y, false); + size_type which = _m_which(arg.pos, false); if(impl_->which == which) { ::nana::arg_toolbar arg{ *widget_, which }; @@ -372,89 +343,47 @@ namespace nana impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted); } - _m_draw(); + refresh(graph); API::lazy_refresh(); } } - drawer::size_type drawer::_m_which(int x, int y, bool want_if_disabled) const + drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const { - if(x < 2 || y < 2 || y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos; + if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos; - x -= 2; + pos.x -= 2; - size_type pos = 0; - for(auto m: impl_->cont) + std::size_t index = 0; + for(auto m: impl_->items.container()) { - bool compart = (nullptr == m); + auto px = static_cast(m ? m->pixels : 3); - if(x < static_cast(compart ? 3 : m->pixels)) - return ((compart || (m->enable == false && want_if_disabled == false)) ? npos : pos); + if(pos.x < px) + return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index); - x -= (compart ? 3 : m->pixels); + pos.x -= px; - ++pos; + ++index; } return npos; } - void drawer::_m_draw_background(const ::nana::color& clr) + void drawer::_m_calc_pixels(item_type* item, bool force) { - graph_->gradual_rectangle(graph_->size(), clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true); - } - - void drawer::_m_draw() - { - int x = 2, y = 2; - - auto bgcolor = API::bgcolor(widget_->handle()); - graph_->set_text_color(bgcolor); - _m_draw_background(bgcolor); - - item_renderer ir(*graph_, impl_->textout, impl_->scale, bgcolor); - size_type index = 0; - - for(auto item : impl_->cont) + if (item && (force || (0 == item->pixels))) { - if(item) - { - _m_fill_pixels(item, false); - ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal)); - x += item->pixels; - } - else - { - graph_->line({ x + 2, y + 2 }, { x + 2, y + static_cast(impl_->scale + ir.extra_size) - 4 }, { 0x80, 0x80, 0x80 }); - x += 6; - } - ++index; - } - } + if (item->text.size()) + item->textsize = impl_->graph_ptr->text_extent_size(item->text); - void drawer::_m_owner_sized(const arg_resized& arg) - { - auto wd = widget_->handle(); - API::window_size(wd, nana::size(arg.width, widget_->size().height)); - _m_draw(); - API::update_window(wd); - } - - void drawer::_m_fill_pixels(item_type* item, bool force) - { - if(item && (force || (0 == item->pixels))) - { - if(item->text.size()) - item->textsize = graph_->text_extent_size(item->text); - - if(item->image.empty() == false) + if (item->image.empty() == false) item->pixels = impl_->scale + item_renderer::extra_size; - if(item->textsize.width && impl_->textout) + if (item->textsize.width && impl_->textout) item->pixels += item->textsize.width + 8; } } - //};//class drawer - + //class drawer }//end namespace toolbar }//end namespace drawerbase @@ -469,33 +398,48 @@ namespace nana create(wd, r, visible); } - void toolbar::append() + void toolbar::separate() { - get_drawer_trigger().append(); + get_drawer_trigger().items().separate(); API::refresh_window(handle()); } void toolbar::append(const nana::string& text, const nana::paint::image& img) { - get_drawer_trigger().append(text, img); + get_drawer_trigger().items().push_back(text, img); API::refresh_window(handle()); } void toolbar::append(const nana::string& text) { - get_drawer_trigger().append(text, nana::paint::image()); + get_drawer_trigger().items().push_back(text, {}); API::refresh_window(this->handle()); } - bool toolbar::enable(size_type n) const + bool toolbar::enable(size_type pos) const { - return get_drawer_trigger().enable(n); + auto & items = get_drawer_trigger().items(); + + if (items.size() <= pos) + return false; + + auto m = items.at(pos); + return (m && m->enable); } - void toolbar::enable(size_type n, bool eb) + void toolbar::enable(size_type pos, bool eb) { - if(get_drawer_trigger().enable(n, eb)) - API::refresh_window(this->handle()); + auto & items = get_drawer_trigger().items(); + + if (items.size() > pos) + { + auto m = items.at(pos); + if (m && (m->enable != eb)) + { + m->enable = eb; + API::refresh_window(this->handle()); + } + } } void toolbar::scale(unsigned s) @@ -503,5 +447,5 @@ namespace nana get_drawer_trigger().scale(s); API::refresh_window(handle()); } - //}; class toolbar + //end class toolbar }//end namespace nana From 331f19e679662eec5d1f91dc75517ca40a813f5b Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 2 Jun 2015 03:44:35 +0800 Subject: [PATCH 34/49] fix menu image issue --- include/nana/gui/widgets/listbox.hpp | 1 - include/nana/gui/widgets/menu.hpp | 2 +- source/gui/widgets/menu.cpp | 7 ++++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 87309008..8720d5d5 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -17,7 +17,6 @@ #include "widget.hpp" #include #include -//#include #include #include diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 883760cf..512d30d7 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -108,7 +108,7 @@ namespace nana virtual void background(graph_reference, window) = 0; virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0; - virtual void item_image(graph_reference, const nana::point&, const paint::image&) = 0; + virtual void item_image(graph_reference, const nana::point&, unsigned image_px, const paint::image&) = 0; virtual void item_text(graph_reference, const nana::point&, const nana::string&, unsigned text_pixels, const attr&) = 0; virtual void sub_arrow(graph_reference, const nana::point&, unsigned item_pixels, const attr&) = 0; }; diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 9f6ec24c..1050affa 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -144,9 +144,9 @@ namespace nana } } - void item_image(graph_reference graph, const nana::point& pos, const paint::image& img) + void item_image(graph_reference graph, const nana::point& pos, unsigned image_px, const paint::image& img) { - img.paste(graph, pos.x, pos.y); + img.stretch(img.size(), graph, { pos, ::nana::size(image_px, image_px)}); } void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at) @@ -524,6 +524,7 @@ namespace nana renderer->background(*graph_, *widget_); const unsigned item_h_px = _m_item_height(); + const unsigned image_px = item_h_px - 2; nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px); unsigned strpixels = item_r.width - 60; @@ -552,7 +553,7 @@ namespace nana nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); if(m.image.empty() == false) - renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image); + renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + static_cast(item_h_px - image_px) / 2 - 1), image_px, m.image); renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); From e8ae11e20872363bc4c382168e18e333c5f75043 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 10 Jun 2015 06:53:58 +0800 Subject: [PATCH 35/49] fix a refreshing issue bad refreshing when a lite_widget is destroying if the lite_widget's parent is also a type of lite_widget --- include/nana/detail/win32/platform_spec.hpp | 7 +++ include/nana/gui/detail/bedrock.hpp | 2 +- include/nana/gui/detail/drawer.hpp | 2 +- include/nana/gui/detail/effects_renderer.hpp | 41 ++++++++++++-- include/nana/gui/detail/window_manager.hpp | 4 +- source/gui/detail/drawer.cpp | 12 ++-- source/gui/detail/linux_X11/bedrock.cpp | 2 +- source/gui/detail/win32/bedrock.cpp | 17 ++++-- source/gui/detail/window_manager.cpp | 58 +++++++++----------- 9 files changed, 96 insertions(+), 49 deletions(-) diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp index 9e735f99..39f21366 100644 --- a/include/nana/detail/win32/platform_spec.hpp +++ b/include/nana/detail/win32/platform_spec.hpp @@ -55,6 +55,13 @@ namespace detail unsigned ignore; //determinate that pos or size would be ignored. }; + struct map_thread + { + rectangle update_area; + bool ignore_update_area; + bool forced; + }; + enum { tray = 0x501, diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 1ae2a41d..501a3c8c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -42,7 +42,7 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void map_thread_root_buffer(core_window_t*, bool forced); + void map_thread_root_buffer(core_window_t*, bool forced, const rectangle* update_area = nullptr); static int inc_window(unsigned tid = 0); thread_context* open_thread_context(unsigned tid = 0); thread_context* get_thread_context(unsigned tid = 0); diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index f6948a45..121c84b8 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -110,7 +110,7 @@ namespace nana void key_char(const arg_keyboard&); void key_release(const arg_keyboard&); void shortkey(const arg_keyboard&); - void map(window, bool forced); //Copy the root buffer to screen + void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen void refresh(); drawer_trigger* realizer() const; void attached(widget&, drawer_trigger&); diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 91daf849..b9b1b785 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -13,9 +13,9 @@ namespace nana{ { edge_nimbus_renderer() = default; public: - typedef CoreWindow core_window_t; - typedef window_layout window_layer; - typedef nana::paint::graphics & graph_reference; + using core_window_t = CoreWindow; + using window_layer = window_layout; + using graph_reference = ::nana::paint::graphics&; static edge_nimbus_renderer& instance() { @@ -28,7 +28,34 @@ namespace nana{ return 2; } - bool render(core_window_t * wd, bool forced) + void erase(core_window_t* wd) + { + if (effects::edge_nimbus::none == wd->effect.edge_nimbus) + return; + + core_window_t * root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + for (auto i = nimbus.cbegin(); i != nimbus.cend(); ++i) + { + if (i->window == wd) + { + auto pixels = weight(); + rectangle r{wd->pos_root, wd->dimension}; + r.x -= static_cast(pixels); + r.y -= static_cast(pixels); + r.width += static_cast(pixels << 1); + r.height += static_cast(pixels << 1); + + root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); + + nimbus.erase(i); + break; + } + } + } + + bool render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) { bool rendered = false; core_window_t * root_wd = wd->root_widget; @@ -49,8 +76,12 @@ namespace nana{ { if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) { - if(action.window == wd) + if (action.window == wd) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(r), r); rendered = true; + } //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 37c9c150..ba6aa451 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -150,9 +150,9 @@ namespace detail core_window_t* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*, bool forced); + void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); - bool update(core_window_t*, bool redraw, bool force); + bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); void refresh_tree(core_window_t*); bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen); diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 3b9702a3..8c176b4b 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -240,7 +240,7 @@ namespace nana _m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey); } - void drawer::map(window wd, bool forced) //Copy the root buffer to screen + void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen { if(wd) { @@ -262,11 +262,15 @@ namespace nana #endif } - if (false == edge_nimbus_renderer_t::instance().render(iwd, forced)) + if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) { - nana::rectangle vr; - if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + rectangle vr; + if (bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y); + } } if(owns_caret) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 44ccef61..1a5a1ecc 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -167,7 +167,7 @@ namespace detail delete impl_; } - void bedrock::map_thread_root_buffer(core_window_t*, bool forced) + void bedrock::map_thread_root_buffer(core_window_t*, bool forced, const rectangle*) { //GUI in X11 is thread-independent, so no implementation. } diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 4a9d0f11..1bb25cc9 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -338,9 +338,14 @@ namespace detail return bedrock_object; } - void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced) + void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced, const rectangle* update_area) { - ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), static_cast(forced ? TRUE : FALSE)); + auto stru = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread))); + if (stru) + { + if (FALSE == ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), reinterpret_cast(stru))) + ::HeapFree(::GetProcessHeap(), 0, stru); + } } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -591,8 +596,12 @@ namespace detail } return true; case nana::detail::messages::map_thread_root_buffer: - bedrock.wd_manager.map(reinterpret_cast(wParam), (TRUE == lParam)); - ::UpdateWindow(wd); + { + auto stru = reinterpret_cast(lParam); + bedrock.wd_manager.map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); + ::UpdateWindow(wd); + ::HeapFree(::GetProcessHeap(), 0, stru); + } return true; case nana::detail::messages::remote_thread_move_window: { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index b7719985..7f8da08b 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -372,21 +372,26 @@ namespace detail //@brief: Delete the window handle void window_manager::destroy(core_window_t* wd) { - core_window_t* parent = nullptr; + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + rectangle update_area(wd->pos_owner, wd->dimension); + + auto parent = wd->parent; + if (parent) + utl::erase(parent->children, wd); + + _m_destroy(wd); + + while (parent && (parent->other.category == ::nana::category::flags::lite_widget)) { - //Thread-Safe Required! - std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd) == false) return; - - if (wd->parent) - { - parent = wd->parent; - utl::erase(wd->parent->children, wd); - } - - _m_destroy(wd); + update_area.x += parent->pos_owner.x; + update_area.y += parent->pos_owner.y; + parent = parent->parent; } - update(parent, false, false); + + update(parent, false, false, &update_area); } //destroy_handle @@ -672,7 +677,7 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd, bool forced) + void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -680,12 +685,12 @@ namespace detail { //Copy the root buffer that wd specified into DeviceContext #if defined(NANA_LINUX) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); #elif defined(NANA_WINDOWS) if(nana::system::this_thread_id() == wd->thread_id) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); else - bedrock::instance().map_thread_root_buffer(wd, forced); + bedrock::instance().map_thread_root_buffer(wd, forced, update_area); #endif } } @@ -694,7 +699,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool forced) + bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -705,7 +710,7 @@ namespace detail if(forced || (false == wd->belong_to_lazy())) { wndlayout_type::paint(wd, redraw, false); - this->map(wd, forced); + this->map(wd, forced, update_area); } else { @@ -1252,18 +1257,9 @@ namespace detail if (!established) { - if (effects::edge_nimbus::none != wd->effect.edge_nimbus) - { - auto & cont = root_attr->effects_edge_nimbus; - for (auto i = cont.begin(); i != cont.end(); ++i) - { - if (i->window == wd) - { - cont.erase(i); - break; - } - } - } + //remove the window from edge nimbus effect when it is destroying + using edge_nimbus = detail::edge_nimbus_renderer; + edge_nimbus::instance().erase(wd); } else if (pa_root_attr != root_attr) { From 7dae0861629dac1f87a077a1c88e0ca89588809a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 15 Jun 2015 22:31:03 +0800 Subject: [PATCH 36/49] fix caret and tab switch on invisible widgets(#62) --- include/nana/gui/detail/window_manager.hpp | 10 +- source/gui/detail/bedrock_pi.cpp | 11 +++ source/gui/detail/drawer.cpp | 2 +- source/gui/detail/win32/bedrock.cpp | 2 +- source/gui/detail/window_manager.cpp | 101 ++++++++++++--------- source/gui/programming_interface.cpp | 2 +- 6 files changed, 77 insertions(+), 51 deletions(-) diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index ba6aa451..2d3a217c 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -87,13 +87,11 @@ namespace detail std::vector stack_; }; public: - typedef native_window_type native_window; - typedef revertible_mutex mutex_type; + using native_window = native_window_type; + using mutex_type = revertible_mutex; - typedef basic_window core_window_t; - typedef std::vector cont_type; - - typedef window_layout wndlayout_type; + using core_window_t = basic_window; + using window_layer = window_layout; window_manager(); ~window_manager(); diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 7843fbaa..e76b0686 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -63,6 +63,17 @@ namespace nana arg.window_handle = reinterpret_cast(wd); if (emit(event_code::expose, wd, arg, false, get_thread_context())) { + if (wd->together.caret) + { + if (exposed) + { + if (wd->root_widget->other.attribute.root->focus == wd) + wd->together.caret->visible(true); + } + else + wd->together.caret->visible(false); + } + if (!exposed) { if (category::flags::root != wd->other.category) diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 8c176b4b..0170ec0d 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -265,7 +265,7 @@ namespace nana if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) { rectangle vr; - if (bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + if (bedrock_type::window_manager_t::window_layer::read_visual_rectangle(iwd, vr)) { if (update_area) ::nana::overlap(*update_area, rectangle(vr), vr); diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 1bb25cc9..daeb369d 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1400,7 +1400,7 @@ namespace detail if(msgwnd) { - if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab + if((wParam == 9) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab { auto the_next = brock.wd_manager.tabstop(msgwnd, (::GetKeyState(VK_SHIFT) >= 0)); if(the_next) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 7f8da08b..44444659 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -428,35 +428,34 @@ namespace detail { //Thread-Safe Required! std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd)) + if (!impl_->wd_register.available(wd)) + return false; + + if(visible != wd->visible) { - if(visible != wd->visible) + native_window_type nv = nullptr; + switch(wd->other.category) { - native_window_type nv = nullptr; - switch(wd->other.category) - { - case category::root_tag::value: - nv = wd->root; break; - case category::frame_tag::value: - nv = wd->other.attribute.frame->container; break; - default: //category::widget_tag, category::lite_widget_tag - break; - } - - if(visible && wd->effect.bground) - wndlayout_type::make_bground(wd); - - //Don't set the visible attr of a window if it is a root. - //The visible attr of a root will be set in the expose event. - if(category::root_tag::value != wd->other.category) - bedrock::instance().event_expose(wd, visible); - - if(nv) - native_interface::show_window(nv, visible, wd->flags.take_active); + case category::root_tag::value: + nv = wd->root; break; + case category::frame_tag::value: + nv = wd->other.attribute.frame->container; break; + default: //category::widget_tag, category::lite_widget_tag + break; } - return true; + + if(visible && wd->effect.bground) + window_layer::make_bground(wd); + + //Don't set the visible attr of a window if it is a root. + //The visible attr of a root will be set in the expose event. + if(category::flags::root != wd->other.category) + bedrock::instance().event_expose(wd, visible); + + if(nv) + native_interface::show_window(nv, visible, wd->flags.take_active); } - return false; + return true; } window_manager::core_window_t* window_manager::find_window(native_window_type root, int x, int y) @@ -645,7 +644,7 @@ namespace detail if(wd->effect.bground && wd->parent) { wd->other.glass_buffer.make(sz); - wndlayout_type::make_bground(wd); + window_layer::make_bground(wd); } } } @@ -709,13 +708,13 @@ namespace detail { if(forced || (false == wd->belong_to_lazy())) { - wndlayout_type::paint(wd, redraw, false); + window_layer::paint(wd, redraw, false); this->map(wd, forced, update_area); } else { if(redraw) - wndlayout_type::paint(wd, true, false); + window_layer::paint(wd, true, false); if(wd->other.upd_state == core_window_t::update_state::lazy) wd->other.upd_state = core_window_t::update_state::refresh; } @@ -730,7 +729,7 @@ namespace detail //It's not worthy to redraw if visible is false if (impl_->wd_register.available(wd) && wd->visible && wd->visible_parents()) - wndlayout_type::paint(wd, true, true); + window_layer::paint(wd, true, true); } //do_lazy_refresh @@ -751,7 +750,7 @@ namespace detail { if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen) { - wndlayout_type::paint(wd, false, false); + window_layer::paint(wd, false, false); this->map(wd, force_copy_to_screen); } else if (effects::edge_nimbus::none != wd->effect.edge_nimbus) @@ -762,7 +761,7 @@ namespace detail } } else - wndlayout_type::paint(wd, true, false); //only refreshing if it has an invisible parent + window_layer::paint(wd, true, false); //only refreshing if it has an invisible parent } wd->other.upd_state = core_window_t::update_state::none; return true; @@ -782,7 +781,7 @@ namespace detail result.make(wd->drawer.graphics.size()); result.bitblt(0, 0, wd->drawer.graphics); - wndlayout_type::paste_children_to_graphics(wd, result); + window_layer::paste_children_to_graphics(wd, result); return true; } @@ -791,7 +790,7 @@ namespace detail //Thread-Safe Required! std::lock_guard lock(mutex_); return (impl_->wd_register.available(wd) ? - wndlayout_type::read_visual_rectangle(wd, r) : + window_layer::read_visual_rectangle(wd, r) : false); } @@ -1020,13 +1019,8 @@ namespace detail } } - auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* + window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward) { - //Thread-Safe Required! - std::lock_guard lock(mutex_); - if (!impl_->wd_register.available(wd)) - return nullptr; - auto & tabs = wd->root_widget->other.attribute.root->tabstop; if (tabs.size()) { @@ -1041,7 +1035,7 @@ namespace detail if (i != end) { ++i; - core_window_t* ts = (i != end ? (*i) : tabs.front()); + window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front()); return (ts != wd ? ts : 0); } else @@ -1058,6 +1052,29 @@ namespace detail return nullptr; } + auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* + { + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (!impl_->wd_register.available(wd)) + return nullptr; + + auto new_stop = get_tabstop(wd, forward); + + while (new_stop) + { + if (wd == new_stop) + break; + + if (new_stop->flags.enabled && new_stop->visible) + return new_stop; + + new_stop = get_tabstop(new_stop, forward); + } + + return nullptr; + } + void window_manager::remove_trash_handle(unsigned tid) { impl_->wd_register.delete_trash(tid); @@ -1068,7 +1085,7 @@ namespace detail //Thread-Safe Required! std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) - return wndlayout_type::enable_effects_bground(wd, enabled); + return window_layer::enable_effects_bground(wd, enabled); return false; } @@ -1369,7 +1386,7 @@ namespace detail brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); _m_disengage(wd, nullptr); - wndlayout_type::enable_effects_bground(wd, false); + window_layer::enable_effects_bground(wd, false); wd->drawer.detached(); impl_->signal.call_signal(wd, signals::code::destroy, signals_); diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index d6f8b483..254b8619 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -721,7 +721,7 @@ namespace API if(restrict::window_manager.available(iwd) && (iwd->flags.enabled != enabled)) { iwd->flags.enabled = enabled; - restrict::window_manager.update(iwd, true, false); + restrict::window_manager.update(iwd, true, true); if(category::flags::root == iwd->other.category) restrict::interface_type::enable_window(iwd->root, enabled); } From 5982f8c7bfcb29748aaf1eb509d289dbde85ebf8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 16 Jun 2015 00:12:09 +0800 Subject: [PATCH 37/49] fix a crash error when click on an empty category of listbox --- source/gui/widgets/listbox.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 9c8eccf7..8b2af38f 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1591,7 +1591,7 @@ namespace nana } /// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_ - bool categ_selected(size_type cat, bool sel); + void categ_selected(size_type cat, bool sel); void reverse_categ_selected(size_type categ) { @@ -2481,21 +2481,16 @@ namespace nana return list_str ; } - bool es_lister::categ_selected(size_type cat, bool sel) + void es_lister::categ_selected(size_type cat, bool sel) { - bool changed = false; // we need this?? - cat_proxy cpx{ess_,cat}; for (item_proxy &it : cpx ) { if (it.selected() != sel) - changed = true; - it.select(sel); + it.select(sel); } last_selected_abs = last_selected_dpl = index_pair {cat, npos}; - - return changed; // we need this?? } class drawer_header_impl @@ -3823,6 +3818,11 @@ namespace nana //Behavior of a container item_proxy cat_proxy::begin() const { + auto i = ess_->lister.cat_container().begin(); + std::advance(i, pos_); + if (i->items.empty()) + return end(); + return item_proxy(ess_, index_pair(pos_, 0)); } From e2cf5452d50015854efba498c9861b8de4e0a7cd Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 17 Jun 2015 00:07:20 +0800 Subject: [PATCH 38/49] fix a charset issue --- source/charset.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/charset.cpp b/source/charset.cpp index c4a0f256..7e952503 100644 --- a/source/charset.cpp +++ b/source/charset.cpp @@ -799,7 +799,7 @@ namespace nana switch(utf_x_) { case unicode::utf8: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) strbuf = detail::utf8_to_utf16(data_, true); detail::put_utf16char(strbuf, 0, true); #else @@ -808,7 +808,7 @@ namespace nana #endif break; case unicode::utf16: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) strbuf = data_; detail::put_utf16char(strbuf, 0, true); #else @@ -817,7 +817,7 @@ namespace nana #endif break; case unicode::utf32: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) strbuf = detail::utf32_to_utf16(data_); detail::put_utf16char(strbuf, 0, true); #else @@ -907,21 +907,21 @@ namespace nana switch(utf_x_) { case unicode::utf8: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) bytes = detail::utf8_to_utf16(data_, true); #else bytes = detail::utf8_to_utf32(data_, true); #endif break; case unicode::utf16: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) bytes = data_; #else bytes = detail::utf16_to_utf32(data_); #endif break; case unicode::utf32: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) bytes = detail::utf32_to_utf16(data_); #else bytes = data_; @@ -984,19 +984,19 @@ namespace nana switch(encoding) { case unicode::utf8: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) return detail::utf16_to_utf8(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); #else return detail::utf32_to_utf8(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); #endif case unicode::utf16: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)); #else return detail::utf32_to_utf16(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); #endif case unicode::utf32: -#if defined(NANA_MINGW) +#if defined(NANA_WINDOWS) return detail::utf16_to_utf32(std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t))); #else return std::string(reinterpret_cast(data_.c_str()), data_.size() * sizeof(wchar_t)); From bdf928a9e8798e7df93da36b021f68605f8ba3cf Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 22 Jun 2015 23:00:48 +0800 Subject: [PATCH 39/49] fix an infinit loop issue when pressing tab key if all tabstop widgets are invisible --- source/gui/detail/window_manager.cpp | 68 +++++++++++++++++----------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 44444659..ba6af080 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1019,35 +1019,35 @@ namespace detail } } + + // preconditions of get_tabstop: tabstop is not empty and at least one window is visible window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward) { auto & tabs = wd->root_widget->other.attribute.root->tabstop; - if (tabs.size()) + + if (forward) { - if (forward) // + if (detail::tab_type::none == wd->flags.tab) + return (tabs.front()); + else if (detail::tab_type::tabstop & wd->flags.tab) { - if (detail::tab_type::none == wd->flags.tab) - return (tabs.front()); - else if (detail::tab_type::tabstop & wd->flags.tab) + auto end = tabs.cend(); + auto i = std::find(tabs.cbegin(), end, wd); + if (i != end) { - auto end = tabs.cend(); - auto i = std::find(tabs.cbegin(), end, wd); - if (i != end) - { - ++i; - window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front()); - return (ts != wd ? ts : 0); - } - else - return tabs.front(); + ++i; + window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front()); + return (ts != wd ? ts : 0); } + else + return tabs.front(); } - else if (tabs.size() > 1) //at least 2 elments in tabs is required when moving perviously. - { - auto i = std::find(tabs.cbegin(), tabs.cend(), wd); - if (i != tabs.cend()) - return (tabs.cbegin() == i ? tabs.back() : *(i - 1)); - } + } + else if (tabs.size() > 1) //at least 2 elments in tabs are required when moving backward. + { + auto i = std::find(tabs.cbegin(), tabs.cend(), wd); + if (i != tabs.cend()) + return (tabs.cbegin() == i ? tabs.back() : *(i - 1)); } return nullptr; } @@ -1059,17 +1059,31 @@ namespace detail if (!impl_->wd_register.available(wd)) return nullptr; - auto new_stop = get_tabstop(wd, forward); + auto & tabs = wd->root_widget->other.attribute.root->tabstop; + if (tabs.empty()) + return nullptr; - while (new_stop) + bool precondition = false; + for (auto & tab_wd : tabs) { - if (wd == new_stop) + if (tab_wd->visible) + { + precondition = true; break; + } + } - if (new_stop->flags.enabled && new_stop->visible) - return new_stop; + if (precondition) + { + auto new_stop = get_tabstop(wd, forward); - new_stop = get_tabstop(new_stop, forward); + while (new_stop && (wd != new_stop)) + { + if (new_stop->flags.enabled && new_stop->visible) + return new_stop; + + new_stop = get_tabstop(new_stop, forward); + } } return nullptr; From d528b5c94d30f36f73196ab7ec5b527aa2542764 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 23 Jun 2015 00:11:47 +0800 Subject: [PATCH 40/49] fix an issue that caret doesn't move when moving the parent widget. --- include/nana/gui/detail/inner_fwd_implement.hpp | 1 - source/gui/detail/linux_X11/bedrock.cpp | 6 +++++- source/gui/detail/win32/bedrock.cpp | 8 +++----- source/gui/detail/window_manager.cpp | 15 +++++++-------- source/gui/widgets/skeletons/text_editor.cpp | 2 ++ 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index 5384aec4..833c7668 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -121,7 +121,6 @@ namespace nana{ { core_window_t* pressed{nullptr}; //The handle to a window which is being pressed core_window_t* hovered{nullptr}; //the latest window that mouse moved - bool tabstop_focus_changed{false}; //KeyDown may set it true, if it is true KeyChar will ignore the message }condition; root_misc(core_window_t * wd, unsigned width, unsigned height) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 1a5a1ecc..d484cbb1 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -1032,7 +1032,6 @@ namespace detail { brock.wd_manager.set_focus(the_next, false); brock.wd_manager.do_lazy_refresh(the_next, true); - root_runtime->condition.tabstop_focus_changed = true; } } else if(keyboard::alt == keychar) @@ -1081,6 +1080,7 @@ namespace detail break; } case XLookupChars: + if (msgwnd->flags.enabled) { const ::nana::char_t* charbuf; #if defined(NANA_UNICODE) @@ -1097,6 +1097,10 @@ namespace detail arg.ignore = false; arg.key = charbuf[i]; + // When tab is pressed, only tab-eating mode is allowed + if ((keyboard::tab == arg.key) && !(msgwnd->flags.tab & tab_type::eating)) + continue; + if(context.is_alt_pressed) { arg.ctrl = arg.shift = false; diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index daeb369d..8cd5231c 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1408,7 +1408,6 @@ namespace detail brock.wd_manager.set_focus(the_next, false); brock.wd_manager.do_lazy_refresh(msgwnd, false); brock.wd_manager.do_lazy_refresh(the_next, true); - root_runtime->condition.tabstop_focus_changed = true; } } else @@ -1437,9 +1436,10 @@ namespace detail break; case WM_CHAR: msgwnd = brock.focus(); - if(false == root_runtime->condition.tabstop_focus_changed) + if (msgwnd && msgwnd->flags.enabled) { - if(msgwnd && msgwnd->flags.enabled) + // When tab is pressed, only tab-eating mode is allowed + if ((9 != wParam) || (msgwnd->flags.tab & tab_type::eating)) { arg_keyboard arg; arg.evt_code = event_code::key_char; @@ -1455,8 +1455,6 @@ namespace detail brock.wd_manager.do_lazy_refresh(msgwnd, false); } } - else - root_runtime->condition.tabstop_focus_changed = false; return 0; case WM_KEYUP: if(wParam != 18) //MUST NOT BE AN ALT diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index ba6af080..30c497fa 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -493,9 +493,6 @@ namespace detail wd->pos_owner.y = y; _m_move_core(wd, delta); - if(wd->together.caret && wd->together.caret->visible()) - wd->together.caret->update(); - auto &brock = bedrock::instance(); arg_move arg; arg.window_handle = reinterpret_cast(wd); @@ -522,7 +519,7 @@ namespace detail auto & brock = bedrock::instance(); bool moved = false; const bool size_changed = (r.width != wd->dimension.width || r.height != wd->dimension.height); - if(wd->other.category != category::root_tag::value) + if(category::flags::root != wd->other.category) { //Move child widgets if(r.x != wd->pos_owner.x || r.y != wd->pos_owner.y) @@ -533,9 +530,6 @@ namespace detail _m_move_core(wd, delta); moved = true; - if(wd->together.caret && wd->together.caret->visible()) - wd->together.caret->update(); - arg_move arg; arg.window_handle = reinterpret_cast(wd); arg.x = r.x; @@ -1425,7 +1419,12 @@ namespace detail if(wd->other.category != category::root_tag::value) //A root widget always starts at (0, 0) and its childs are not to be changed { wd->pos_root += delta; - if(wd->other.category == category::frame_tag::value) + if (category::flags::frame != wd->other.category) + { + if (wd->together.caret && wd->together.caret->visible()) + wd->together.caret->update(); + } + else native_interface::move_window(wd->other.attribute.frame->container, wd->pos_root.x, wd->pos_root.y); for (auto child : wd->children) diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 0a2f9261..69cf0b6a 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1482,6 +1482,8 @@ namespace nana{ namespace widgets behavior_->pre_calc_lines(width_pixels()); _m_scrollbar(); + + move_caret(points_.caret); return true; } From e479689946b7d23d202a6863e3e2d886654d91af Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 25 Jun 2015 01:32:54 +0800 Subject: [PATCH 41/49] fix a crash error which is caused by the focus of submenu(#65) --- source/gui/widgets/menu.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 1050affa..807d2b75 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -700,15 +700,18 @@ namespace nana class menu_window : public widget_object { - typedef menu_drawer drawer_type; - typedef widget_object base_type; + using drawer_type = menu_drawer; + using base_type = widget_object; public: - typedef menu_builder::item_type item_type; + using item_type = menu_builder::item_type; - menu_window(window wd, const point& pos, renderer_interface * rdptr) + + menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr) + //add a is_wd_parent_menu to determine whether the menu wants the focus. + //if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald()), - want_focus_(nullptr == wd || (API::focus_window() != wd)), - event_focus_(nullptr) + want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) }, + event_focus_{ nullptr } { caption(STR("nana menu window")); get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); }); @@ -1012,7 +1015,7 @@ namespace nana pos.x += sbm->gaps.x; pos.y += sbm->gaps.y; - menu_window & mwnd = form_loader()(handle(), pos, mdtrigger.renderer); + menu_window & mwnd = form_loader()(handle(), true, pos, mdtrigger.renderer); mwnd.state_.self_submenu = true; submenu_.child = & mwnd; submenu_.child->submenu_.parent = this; @@ -1294,7 +1297,7 @@ namespace nana { close(); - impl_->uiobj = &(form_loader()(wd, point(x, y), &(*impl_->mbuilder.renderer()))); + impl_->uiobj = &(form_loader()(wd, false, point(x, y), &(*impl_->mbuilder.renderer()))); impl_->uiobj->events().destroy.connect_unignorable([this]{ impl_->uiobj = nullptr; if (impl_->destroy_answer) From 1dd61ffb2421a75fa28ad310b4c9466fbbe1f81a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 25 Jun 2015 02:00:57 +0800 Subject: [PATCH 42/49] fix an explicit conversion error from ifstream to bool --- source/detail/linux_X11/platform_spec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/detail/linux_X11/platform_spec.cpp b/source/detail/linux_X11/platform_spec.cpp index f53c046b..c8ccf682 100644 --- a/source/detail/linux_X11/platform_spec.cpp +++ b/source/detail/linux_X11/platform_spec.cpp @@ -44,7 +44,7 @@ namespace detail bool conf::open(const char* file) { ifs_.open(file); - return static_cast(ifs_ != 0); + return static_cast(ifs_); } std::string conf::value(const char* key) From 8be566214c153a129705ebe4f4cbf50a8c069acb Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 26 Jun 2015 23:59:28 +0800 Subject: [PATCH 43/49] fix a caret issue which happens when parent widget is hidden --- include/nana/gui/detail/basic_window.hpp | 4 +++- source/gui/detail/basic_window.cpp | 25 ++++++++++++++++++++++++ source/gui/detail/bedrock_pi.cpp | 9 +++++---- source/gui/detail/win32/bedrock.cpp | 2 +- source/gui/detail/window_layout.cpp | 2 +- source/gui/detail/window_manager.cpp | 6 +++--- 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 659f4316..c4945552 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -118,9 +118,11 @@ namespace detail bool is_ancestor_of(const basic_window* wd) const; bool visible_parents() const; + bool displayed() const; bool belong_to_lazy() const; + const basic_window * child_caret() const; //Returns a child which owns a caret - bool is_draw_through() const; ///< Determines whether it is a draw-through window. + bool is_draw_through() const; // Determines whether it is a draw-through window. public: //Override event_holder bool set_events(const std::shared_ptr&) override; diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 96aec1fa..33a91ca8 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -282,6 +282,11 @@ namespace nana return true; } + bool basic_window::displayed() const + { + return (visible && visible_parents()); + } + bool basic_window::belong_to_lazy() const { for (auto wd = this; wd; wd = wd->parent) @@ -292,6 +297,26 @@ namespace nana return false; } + const basic_window* get_child_caret(const basic_window* wd, bool this_is_a_child) + { + if (this_is_a_child && wd->together.caret) + return wd; + + for (auto child : wd->children) + { + auto caret_wd = get_child_caret(child, true); + if (caret_wd) + return caret_wd; + } + + return nullptr; + } + + const basic_window * basic_window::child_caret() const + { + return get_child_caret(this, false); + } + bool basic_window::is_draw_through() const { if (::nana::category::flags::root == this->other.category) diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index e76b0686..ce84ed94 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -63,15 +63,16 @@ namespace nana arg.window_handle = reinterpret_cast(wd); if (emit(event_code::expose, wd, arg, false, get_thread_context())) { - if (wd->together.caret) + const core_window_t * caret_wd = (wd->together.caret ? wd : wd->child_caret()); + if (caret_wd) { if (exposed) { - if (wd->root_widget->other.attribute.root->focus == wd) - wd->together.caret->visible(true); + if (wd->root_widget->other.attribute.root->focus == caret_wd) + caret_wd->together.caret->visible(true); } else - wd->together.caret->visible(false); + caret_wd->together.caret->visible(false); } if (!exposed) diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 8cd5231c..e5635d12 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -363,7 +363,7 @@ namespace detail void bedrock::pump_event(window modal_window, bool is_modal) { const unsigned tid = ::GetCurrentThreadId(); - thread_context * context = this->open_thread_context(tid); + auto context = this->open_thread_context(tid); if(0 == context->window_count) { //test if there is not a window diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index a77eff5f..05867650 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -354,7 +354,7 @@ namespace nana nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); for (auto wd : data_sect.effects_bground_windows) { - if (wd == sigwd || !wd->visible || !wd->visible_parents() || + if (wd == sigwd || !wd->displayed() || (false == overlap(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd))) continue; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 30c497fa..59b54506 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -698,7 +698,7 @@ namespace detail std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd) == false) return false; - if (wd->visible && wd->visible_parents()) + if (wd->displayed()) { if(forced || (false == wd->belong_to_lazy())) { @@ -722,7 +722,7 @@ namespace detail std::lock_guard lock(mutex_); //It's not worthy to redraw if visible is false - if (impl_->wd_register.available(wd) && wd->visible && wd->visible_parents()) + if (impl_->wd_register.available(wd) && wd->displayed()) window_layer::paint(wd, true, true); } @@ -1060,7 +1060,7 @@ namespace detail bool precondition = false; for (auto & tab_wd : tabs) { - if (tab_wd->visible) + if (tab_wd->displayed()) { precondition = true; break; From c245ae82967e4e74b8d46720ff36018849f53e1d Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 29 Jun 2015 07:31:51 +0800 Subject: [PATCH 44/49] fix menu behavioral issues and a menubar delay_restore issue don't delay_restore when arrow keys is pressed --- source/gui/detail/linux_X11/bedrock.cpp | 4 +- source/gui/detail/win32/bedrock.cpp | 5 +- source/gui/widgets/menu.cpp | 358 ++++++++++++------------ 3 files changed, 188 insertions(+), 179 deletions(-) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index d484cbb1..d1632f7c 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -1149,7 +1149,9 @@ namespace detail brock.get_key_state(arg); brock.emit(event_code::key_release, msgwnd, arg, true, &context); } - brock.delay_restore(2); //Restores while key release + + if (context.platform.keychar < keyboard::os_arrow_left || keyboard::os_arrow_down < wParam) + brock.delay_restore(2); //Restores while key release } else { diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index e5635d12..682f371b 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1474,7 +1474,10 @@ namespace detail else brock.set_keyboard_shortkey(false); - brock.delay_restore(2); //Restores while key release + //Do delay restore if key is not arrow_left/right/up/down, otherwise + //A menubar will be restored if the item is empty(not have a menu item) + if (wParam < 37 || 40 < wParam) + brock.delay_restore(2); //Restores while key release break; case WM_CLOSE: { diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 807d2b75..054e639a 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -114,7 +114,7 @@ namespace nana { if(at.item_state == state::active) { - graph.rectangle(r, false, {0xa8, 0xd8, 0xeb}); + graph.rectangle(r, false, static_cast(0xa8d8eb)); nana::point points[4] = { nana::point(r.x, r.y), nana::point(r.x + r.width - 1, r.y), @@ -200,35 +200,35 @@ namespace nana void checked(std::size_t index, bool check) { - if(root_.items.size() > index) + if (root_.items.size() <= index) + return; + + item_type & m = root_.items[index]; + if(check && (checks::option == m.style)) { - item_type & m = root_.items[index]; - if(check && (checks::option == m.style)) + if(index) { - if(index) + std::size_t i = index; + do { - std::size_t i = index; - do - { - item_type& el = root_.items[--i]; - if(el.flags.splitter) break; - - if(checks::option == el.style) - el.flags.checked = false; - }while(i); - } - - for(std::size_t i = index + 1; i < root_.items.size(); ++i) - { - item_type & el = root_.items[i]; + item_type& el = root_.items[--i]; if(el.flags.splitter) break; if(checks::option == el.style) el.flags.checked = false; - } + }while(i); + } + + for(std::size_t i = index + 1; i < root_.items.size(); ++i) + { + item_type & el = root_.items[i]; + if(el.flags.splitter) break; + + if(checks::option == el.style) + el.flags.checked = false; } - m.flags.checked = check; } + m.flags.checked = check; } menu_type& data() @@ -304,7 +304,7 @@ namespace nana : public drawer_trigger { public: - typedef menu_item_type::item_proxy item_proxy; + using item_proxy = menu_item_type::item_proxy; renderer_interface * renderer; @@ -330,12 +330,12 @@ namespace nana detail_.monitor_pos = API::cursor_position(); } - void mouse_move(graph_reference, const arg_mouse& arg) + void mouse_move(graph_reference graph, const arg_mouse& arg) { state_.nullify_mouse = false; - if(track_mouse(arg.pos.x, arg.pos.y)) + if(track_mouse(arg.pos)) { - draw(); + refresh(graph); API::lazy_refresh(); } } @@ -350,9 +350,70 @@ namespace nana state_.nullify_mouse = false; } - void refresh(graph_reference) + void refresh(graph_reference graph) { - draw(); + if (nullptr == menu_) return; + + _m_adjust_window_size(); + + renderer->background(graph, *widget_); + + const unsigned item_h_px = _m_item_height(); + const unsigned image_px = item_h_px - 2; + nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px); + + unsigned strpixels = item_r.width - 60; + + int text_top_off = (item_h_px - graph.text_extent_size(STR("jh({[")).height) / 2; + + std::size_t pos = 0; + for (auto & m : menu_->items) + { + if (m.flags.splitter) + { + graph_->set_color(colors::gray_border); + graph_->line({ item_r.x + 40, item_r.y }, { static_cast(graph.width()) - 1, item_r.y }); + item_r.y += 2; + ++pos; + continue; + } + + renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m); + //Draw item background + renderer->item(*graph_, item_r, attr); + + //Draw text, the text is transformed from orignal for hotkey character + nana::char_t hotkey; + nana::string::size_type hotkey_pos; + nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); + + if (m.image.empty() == false) + renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast(item_h_px - image_px) / 2 - 1), image_px, m.image); + + renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); + + if (hotkey) + { + m.hotkey = hotkey; + if (m.flags.enabled) + { + unsigned off_w = (hotkey_pos ? graph.text_extent_size(text, static_cast(hotkey_pos)).width : 0); + nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1); + int x = item_r.x + 40 + off_w; + int y = item_r.y + text_top_off + hotkey_size.height; + + graph_->set_color(colors::black); + graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }); + } + } + + if (m.sub_menu) + renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); + + item_r.y += item_r.height + 1; + + ++pos; + } } std::size_t active() const @@ -411,21 +472,21 @@ namespace nana state_.active = pos; state_.sub_window = false; - draw(); + refresh(*graph_); return true; } return false; } - bool track_mouse(int x, int y) + bool track_mouse(const ::nana::point& pos) { - if(state_.nullify_mouse == false) + if (!state_.nullify_mouse) { - std::size_t index = _m_get_index_by_pos(x, y); - if(index != state_.active) + std::size_t index = _m_get_index_by_pos(pos.x, pos.y); + if (index != state_.active) { - if((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window) + if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window) return false; state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index; @@ -433,6 +494,7 @@ namespace nana return true; } } + return false; } @@ -451,29 +513,35 @@ namespace nana state_.sub_window = subw; } - menu_type* retrive_sub_menu(nana::point& pos, std::size_t interval) const + menu_type* get_sub(nana::point& pos, unsigned long& tmstamp) const { - if(state_.active != npos && (nana::system::timestamp() - state_.active_timestamp >= interval)) + if (npos == state_.active) + return nullptr; + + auto sub = menu_->items.at(state_.active).sub_menu; + if (sub) { - pos.x = graph_->width() - 2; + pos.x = static_cast(graph_->width()) - 2; pos.y = 2; - std::size_t index = 0; - for(auto & m : menu_->items) + auto index = state_.active; + for (auto & m : menu_->items) { - if(false == m.flags.splitter) + if (m.flags.splitter) { - if(index == state_.active) - break; - - pos.y += _m_item_height() + 1; - } - else pos.y += 2; + continue; + } - ++index; + if (0 == index) + break; + + pos.y += _m_item_height() + 1; + --index; } - return (menu_->items.at(state_.active).sub_menu); + + tmstamp = state_.active_timestamp; + return sub; } return nullptr; } @@ -498,8 +566,7 @@ namespace nana state_.active = index; state_.active_timestamp = nana::system::timestamp(); - draw(); - API::update_window(*widget_); + API::refresh_window(*widget_); return 2; } else if(m.flags.enabled) @@ -514,72 +581,6 @@ namespace nana } return 0; } - - void draw() const - { - if(nullptr == menu_) return; - - _m_adjust_window_size(); - - renderer->background(*graph_, *widget_); - - const unsigned item_h_px = _m_item_height(); - const unsigned image_px = item_h_px - 2; - nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px); - - unsigned strpixels = item_r.width - 60; - - int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2; - - std::size_t pos = 0; - for(auto & m : menu_->items) - { - if(m.flags.splitter) - { - graph_->set_color(colors::gray_border); - graph_->line({ item_r.x + 40, item_r.y }, { static_cast(graph_->width()) - 1, item_r.y }); - item_r.y += 2; - ++pos; - continue; - } - - renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m); - //Draw item background - renderer->item(*graph_, item_r, attr); - - //Draw text, the text is transformed from orignal for hotkey character - nana::char_t hotkey; - nana::string::size_type hotkey_pos; - nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); - - if(m.image.empty() == false) - renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + static_cast(item_h_px - image_px) / 2 - 1), image_px, m.image); - - renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); - - if(hotkey) - { - m.hotkey = hotkey; - if(m.flags.enabled) - { - unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast(hotkey_pos)).width : 0); - nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1); - int x = item_r.x + 40 + off_w; - int y = item_r.y + text_top_off + hotkey_size.height; - - graph_->set_color(colors::black); - graph_->line({ x, y }, { x + static_cast(hotkey_size.width) - 1, y }); - } - } - - if(m.sub_menu) - renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); - - item_r.y += item_r.height + 1; - - ++pos; - } - } private: static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m) { @@ -684,10 +685,10 @@ namespace nana struct state { - std::size_t active; - unsigned long active_timestamp; - unsigned long sub_window: 1; - unsigned long nullify_mouse: 1; + std::size_t active; + unsigned active_timestamp; + bool sub_window: 1; + bool nullify_mouse: 1; }state_; struct widget_detail @@ -722,7 +723,19 @@ namespace nana submenu_.child = submenu_.parent = nullptr; submenu_.object = nullptr; - _m_make_mouse_event(); + state_.mouse_pos = API::cursor_position(); + events().mouse_move.connect_unignorable([this]{ + nana::point pos = API::cursor_position(); + if (pos != state_.mouse_pos) + { + menu_window * root = this; + while (root->submenu_.parent) + root = root->submenu_.parent; + root->state_.auto_popup_submenu = true; + + state_.mouse_pos = pos; + } + }); } void popup(menu_type& menu, bool owner_menubar) @@ -749,13 +762,19 @@ namespace nana _m_key_down(arg); }); - events().mouse_up.connect_unignorable([this]{ - pick(); + events().mouse_down.connect_unignorable([this](const arg_mouse& arg) + { + this->_m_open_sub(0); //Try to open submenu immediately + }); + + events().mouse_up.connect_unignorable([this](const arg_mouse& arg){ + if (arg.left_button) + pick(); }); timer_.interval(100); timer_.elapse([this]{ - this->_m_check_repeatly(); + this->_m_open_sub(500); //Try to open submenu }); timer_.start(); @@ -801,29 +820,27 @@ namespace nana bool submenu(bool enter) { - menu_window * object = this; - while (object->submenu_.child) - object = object->submenu_.child; + menu_window * menu_wd = this; + while (menu_wd->submenu_.child) + menu_wd = menu_wd->submenu_.child; state_.auto_popup_submenu = false; - if (enter) + if (!enter) { - if (object->submenu_.parent) + if (menu_wd->submenu_.parent) { - auto & sub = object->submenu_.parent->submenu_; + auto & sub = menu_wd->submenu_.parent->submenu_; sub.child = nullptr; sub.object = nullptr; - object->close(); + menu_wd->close(); return true; } return false; } - nana::point pos; - menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0); - return object->_m_show_submenu(sbm, pos, true); + return menu_wd->_m_manipulate_sub(0, true); } int send_shortkey(nana::char_t key) @@ -969,63 +986,51 @@ namespace nana } } - void _m_make_mouse_event() + bool _m_manipulate_sub(unsigned long delay_ms, bool forced) { - state_.mouse_pos = API::cursor_position(); - events().mouse_move.connect_unignorable([this]{ - _m_mouse_event(); - }); - } + auto & drawer = get_drawer_trigger(); + ::nana::point pos; + unsigned long tmstamp; - void _m_mouse_event() - { - nana::point pos = API::cursor_position(); - if(pos != state_.mouse_pos) + auto menu_ptr = drawer.get_sub(pos, tmstamp); + + if (menu_ptr == submenu_.object) + return false; + + if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms)) + return false; + + if (submenu_.object && (menu_ptr != submenu_.object)) { - menu_window * root = this; - while(root->submenu_.parent) - root = root->submenu_.parent; - root->state_.auto_popup_submenu = true; - - state_.mouse_pos = pos; - } - } - - bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced) - { - auto & mdtrigger = get_drawer_trigger(); - if(submenu_.object && (sbm != submenu_.object)) - { - mdtrigger.set_sub_window(false); + drawer.set_sub_window(false); submenu_.child->close(); submenu_.child = nullptr; submenu_.object = nullptr; } - if(sbm) + if (menu_ptr) { menu_window * root = this; - while(root->submenu_.parent) + while (root->submenu_.parent) root = root->submenu_.parent; - if((submenu_.object == nullptr) && sbm && (forced || root->state_.auto_popup_submenu)) + if ((submenu_.object == nullptr) && menu_ptr && (forced || root->state_.auto_popup_submenu)) { - sbm->item_pixels = mdtrigger.data()->item_pixels; - sbm->gaps = mdtrigger.data()->gaps; - pos.x += sbm->gaps.x; - pos.y += sbm->gaps.y; + menu_ptr->item_pixels = drawer.data()->item_pixels; + menu_ptr->gaps = drawer.data()->gaps; + pos += menu_ptr->gaps; - menu_window & mwnd = form_loader()(handle(), true, pos, mdtrigger.renderer); + menu_window & mwnd = form_loader()(handle(), true, pos, drawer.renderer); mwnd.state_.self_submenu = true; - submenu_.child = & mwnd; + submenu_.child = &mwnd; submenu_.child->submenu_.parent = this; - submenu_.object = sbm; + submenu_.object = menu_ptr; API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none); - mwnd.popup(*sbm, state_.owner_menubar); - mdtrigger.set_sub_window(true); - if(forced) + mwnd.popup(*menu_ptr, state_.owner_menubar); + drawer.set_sub_window(true); + if (forced) mwnd.goto_next(true); return true; @@ -1034,17 +1039,16 @@ namespace nana return false; } - void _m_check_repeatly() + void _m_open_sub(unsigned delay_ms) //check_repeatly { if(state_.auto_popup_submenu) { - nana::point pos = API::cursor_position(); + auto pos = API::cursor_position(); - drawer_type& drawer = get_drawer_trigger(); API::calc_window_point(handle(), pos); - drawer.track_mouse(pos.x, pos.y); - menu_type* sbm = drawer.retrive_sub_menu(pos, 500); - _m_show_submenu(sbm, pos, false); + get_drawer_trigger().track_mouse(pos); + + _m_manipulate_sub(delay_ms, false); } } private: From 37481a2065a18a16cf0a52097d226bf2830350b4 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 4 Jul 2015 22:56:03 +0800 Subject: [PATCH 45/49] fix ghost image(#62) --- source/gui/detail/window_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 05867650..11d59f9b 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -99,7 +99,7 @@ namespace nana // The result is a rectangle that is a visible area for its ancesters. bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual) { - if (false == wd->visible) return false; + if (! wd->displayed()) return false; visual = rectangle{ wd->pos_root, wd->dimension }; From 0d14620052da6c50de50bf9e8899a0ae6bacd453 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 5 Jul 2015 16:21:13 +0800 Subject: [PATCH 46/49] fix caret/keyboard issue(#62) pressing space on a button will trigger click event --- include/nana/gui/basis.hpp | 1 + include/nana/gui/detail/drawer.hpp | 59 +++++++++++++++------------- source/gui/detail/drawer.cpp | 43 ++++++++++---------- source/gui/detail/window_manager.cpp | 2 +- source/gui/widgets/button.cpp | 2 +- 5 files changed, 56 insertions(+), 51 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index c0ef0aa5..789ab5c3 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -84,6 +84,7 @@ namespace nana end_of_medium = 0x19, //Ctrl+Y substitute = 0x1A, //Ctrl+Z escape = 0x1B, + space = 0x20, //Space //The following names are intuitive name of ASCII control codes select_all = start_of_headline, diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index 121c84b8..fa62974b 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -23,12 +23,18 @@ namespace nana { class widget; + namespace detail + { + class drawer; + } + class drawer_trigger : ::nana::noncopyable, ::nana::nonmovable { + friend class detail::drawer; public: - typedef widget& widget_reference; - typedef paint::graphics& graph_reference; + using widget_reference = widget&; + using graph_reference = paint::graphics&; virtual ~drawer_trigger(); virtual void attached(widget_reference, graph_reference); //none-const @@ -56,10 +62,11 @@ namespace nana virtual void key_release(graph_reference, const arg_keyboard&); virtual void shortkey(graph_reference, const arg_keyboard&); - void _m_reset_overrided(); - bool _m_overrided() const; private: - bool overrided_{false}; + void _m_reset_overrided(); + bool _m_overrided(event_code) const; + private: + unsigned overrided_{ 0xFFFFFFFF }; }; namespace detail @@ -83,7 +90,7 @@ namespace nana enum class method_state { - unknown, + pending, overrided, not_overrided }; @@ -128,31 +135,27 @@ namespace nana template void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr) { - if (realizer_) + const int pos = static_cast(evt_code); + if (realizer_ && (method_state::not_overrided != mth_state_[pos])) { - const int pos = static_cast(evt_code); - if (method_state::not_overrided != mth_state_[pos]) + _m_bground_pre(); + + if (method_state::pending == mth_state_[pos]) { - _m_bground_pre(); + (realizer_->*mfptr)(graphics, arg); + + //Check realizer, when the window is closed in that event handler, the drawer will be + //detached and realizer will be a nullptr + if(realizer_) + mth_state_[pos] = (realizer_->_m_overrided(evt_code) ? method_state::overrided : method_state::not_overrided); + } + else + (realizer_->*mfptr)(graphics, arg); - if (method_state::unknown == mth_state_[pos]) - { - realizer_->_m_reset_overrided(); - (realizer_->*mfptr)(graphics, arg); - - //Check realizer, when the window is closed in that event handler, the drawer will be - //detached and realizer will be a nullptr - if(realizer_) - mth_state_[pos] = (realizer_->_m_overrided() ? method_state::overrided : method_state::not_overrided); - } - else - (realizer_->*mfptr)(graphics, arg); - - if (_m_lazy_decleared()) - { - _m_draw_dynamic_drawing_object(); - _m_bground_end(); - } + if (_m_lazy_decleared()) + { + _m_draw_dynamic_drawing_object(); + _m_bground_end(); } } } diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 0170ec0d..69c47190 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -34,99 +34,99 @@ namespace nana void drawer_trigger::resizing(graph_reference, const arg_resizing&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::resizing)); } void drawer_trigger::resized(graph_reference graph, const arg_resized&) { - overrided_ = true; + overrided_ |= (1 << static_cast(event_code::resized)); this->refresh(graph); detail::bedrock::instance().thread_context_lazy_refresh(); } void drawer_trigger::move(graph_reference, const arg_move&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::move)); } void drawer_trigger::click(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::click)); } void drawer_trigger::dbl_click(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::dbl_click)); } void drawer_trigger::mouse_enter(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_enter)); } void drawer_trigger::mouse_move(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_move)); } void drawer_trigger::mouse_leave(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_leave)); } void drawer_trigger::mouse_down(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_down)); } void drawer_trigger::mouse_up(graph_reference, const arg_mouse&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_up)); } void drawer_trigger::mouse_wheel(graph_reference, const arg_wheel&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_wheel)); } void drawer_trigger::mouse_dropfiles(graph_reference, const arg_dropfiles&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::mouse_drop)); } void drawer_trigger::focus(graph_reference, const arg_focus&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::focus)); } void drawer_trigger::key_press(graph_reference, const arg_keyboard&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::key_press)); } void drawer_trigger::key_char(graph_reference, const arg_keyboard&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::key_char)); } void drawer_trigger::key_release(graph_reference, const arg_keyboard&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::key_release)); } void drawer_trigger::shortkey(graph_reference, const arg_keyboard&) { - overrided_ = false; + overrided_ &= ~(1 << static_cast(event_code::shortkey)); } void drawer_trigger::_m_reset_overrided() { - overrided_ = true; + overrided_ = 0xFFFFFFFF; } - bool drawer_trigger::_m_overrided() const + bool drawer_trigger::_m_overrided(event_code evt_code) const { - return overrided_; + return 0 != (overrided_ & (1 << static_cast(evt_code))); } //end class drawer_trigger @@ -306,9 +306,10 @@ namespace nana void drawer::attached(widget& wd, drawer_trigger& realizer) { for (auto i = std::begin(mth_state_), end = std::end(mth_state_); i != end; ++i) - *i = method_state::unknown; + *i = method_state::pending; realizer_ = &realizer; + realizer._m_reset_overrided(); realizer.attached(wd, graphics); } diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 59b54506..8a952bf2 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1073,7 +1073,7 @@ namespace detail while (new_stop && (wd != new_stop)) { - if (new_stop->flags.enabled && new_stop->visible) + if (new_stop->flags.enabled && new_stop->displayed()) return new_stop; new_stop = get_tabstop(new_stop, forward); diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 63d8e810..9e660203 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase void trigger::key_char(graph_reference, const arg_keyboard& arg) { - if(arg.key == static_cast(keyboard::enter)) + if (static_cast(keyboard::enter) == arg.key || static_cast(keyboard::space) == arg.key) emit_click(); } From 08deeba0968f463372dd46c98846b8f7035012f9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 5 Jul 2015 23:38:24 +0800 Subject: [PATCH 47/49] fix missing edge_nimbus_effect issue --- include/nana/gui/detail/effects_renderer.hpp | 78 +++++++++++--------- source/gui/detail/bedrock_pi.cpp | 2 +- source/gui/detail/drawer.cpp | 15 +--- source/gui/detail/linux_X11/bedrock.cpp | 9 +-- source/gui/detail/win32/bedrock.cpp | 12 ++- source/gui/detail/window_layout.cpp | 1 - 6 files changed, 56 insertions(+), 61 deletions(-) diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index b9b1b785..6b189d84 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -23,7 +23,7 @@ namespace nana{ return object; } - std::size_t weight() const + unsigned weight() const { return 2; } @@ -55,22 +55,23 @@ namespace nana{ } } - bool render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) + void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) { - bool rendered = false; - core_window_t * root_wd = wd->root_widget; - auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + bool copy_separately = true; + std::vector> rd_set; - if(nimbus.size()) + if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size()) { - core_window_t * focused = root_wd->other.attribute.root->focus; - native_window_type native = root_wd->root; - std::size_t pixels = weight(); + auto root_wd = wd->root_widget; + + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + auto focused = root_wd->other.attribute.root->focus; + + const unsigned pixels = weight(); auto graph = root_wd->root_graph; - std::vector erase; - std::vector> rd_set; nana::rectangle r; for(auto & action : nimbus) { @@ -80,11 +81,11 @@ namespace nana{ { if (update_area) ::nana::overlap(*update_area, rectangle(r), r); - rendered = true; + copy_separately = false; } //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. - if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) + if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) { rd_set.emplace_back(r, action.window); action.rendered = true; @@ -93,29 +94,36 @@ namespace nana{ else if(action.rendered) { action.rendered = false; - erase.push_back(action.window); + + if (action.window == wd) + copy_separately = false; + + ::nana::rectangle erase_r( + action.window->pos_root.x - static_cast(pixels), + action.window->pos_root.y - static_cast(pixels), + static_cast(action.window->dimension.width + (pixels << 1)), + static_cast(action.window->dimension.height + (pixels << 1)) + ); + + graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y); } } - - //Erase - for(auto el : erase) - { - if(el == wd) - rendered = true; - - r.x = el->pos_root.x - static_cast(pixels); - r.y = el->pos_root.y - static_cast(pixels); - r.width = static_cast(el->dimension.width + (pixels << 1)); - r.height = static_cast(el->dimension.height + (pixels << 1)); - - graph->paste(native, r, r.x, r.y); - } - - //Render - for (auto & rd : rd_set) - _m_render_edge_nimbus(rd.second, rd.first); } - return rendered; + + if (copy_separately) + { + rectangle vr; + if (window_layer::read_visual_rectangle(wd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); + wd->root_graph->paste(wd->root, vr, vr.x, vr.y); + } + } + + //Render + for (auto & rd : rd_set) + _m_render_edge_nimbus(rd.second, rd.first); } private: static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd) @@ -134,8 +142,8 @@ namespace nana{ nana::rectangle good_r; if(overlap(r, wd->root_graph->size(), good_r)) { - if( (good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || - (good_r.x + good_r.width > visual.x + visual.width) || (good_r.y + good_r.height > visual.y + visual.height)) + if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || + (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) { auto graph = wd->root_graph; nana::paint::pixel_buffer pixbuf(graph->handle(), r); diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index ce84ed94..fc41706c 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -103,7 +103,7 @@ namespace nana arg.x = x; arg.y = y; if (emit(event_code::move, wd, arg, false, get_thread_context())) - wd_manager.update(wd, true, true); + wd_manager.update(wd, false, true); } } diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 69c47190..f1308677 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -244,8 +244,8 @@ namespace nana { if(wd) { - bedrock_type::core_window_t* iwd = reinterpret_cast(wd); - bedrock_type::core_window_t * caret_wd = iwd->root_widget->other.attribute.root->focus; + auto iwd = reinterpret_cast(wd); + auto caret_wd = iwd->root_widget->other.attribute.root->focus; bool owns_caret = (caret_wd && (caret_wd->together.caret) && (caret_wd->together.caret->visible())); @@ -262,16 +262,7 @@ namespace nana #endif } - if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) - { - rectangle vr; - if (bedrock_type::window_manager_t::window_layer::read_visual_rectangle(iwd, vr)) - { - if (update_area) - ::nana::overlap(*update_area, rectangle(vr), vr); - iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y); - } - } + edge_nimbus_renderer_t::instance().render(iwd, forced, update_area); if(owns_caret) { diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index d1632f7c..65414360 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -937,11 +937,10 @@ namespace detail if(msgwnd->visible && (msgwnd->root_graph->empty() == false)) { nana::detail::platform_scope_guard psg; - nana::detail::drawable_impl_type* drawer_impl = msgwnd->root_graph->handle(); - ::XCopyArea(display, drawer_impl->pixmap, reinterpret_cast(native_window), drawer_impl->context, - xevent.xexpose.x, xevent.xexpose.y, - xevent.xexpose.width, xevent.xexpose.height, - xevent.xexpose.x, xevent.xexpose.y); + //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. + ::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height); + if (!update_area.empty()) + msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); } break; case KeyPress: diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 682f371b..65e29071 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1310,13 +1310,11 @@ namespace detail ::PAINTSTRUCT ps; ::HDC dc = ::BeginPaint(root_window, &ps); - if((ps.rcPaint.left != ps.rcPaint.right) && (ps.rcPaint.bottom != ps.rcPaint.top)) - { - ::BitBlt(dc, - ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, - reinterpret_cast(msgwnd->root_graph->handle()->context), - ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); - } + //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. + ::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); + if (!update_area.empty()) + msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); + ::EndPaint(root_window, &ps); } break; diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 11d59f9b..5734acbe 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -59,7 +59,6 @@ namespace nana if (wd->parent) { std::vector blocks; - blocks.reserve(10); if (read_overlaps(wd, vr, blocks)) { nana::point p_src; From 5f9a98c7bcc6dbded83e2011c5757c09f15c0e11 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 5 Jul 2015 23:57:10 +0800 Subject: [PATCH 48/49] fix a caret issue when set focus to a invisible textbox(#62) --- source/gui/detail/basic_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 33a91ca8..27a6316c 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -109,7 +109,7 @@ namespace nana if(real_visible_state_ != isshow) { real_visible_state_ = isshow; - native_interface::caret_visible(wd_->root, isshow); + native_interface::caret_visible(wd_->root, isshow && wd_->displayed()); } } From 59f355463295e8fea75a5563d614f012c1517c17 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 6 Jul 2015 22:23:05 +0800 Subject: [PATCH 49/49] fix listbox auto-redraw issue --- source/gui/widgets/listbox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 8b2af38f..1a1a7aa3 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -3512,6 +3512,7 @@ namespace nana m.flags.checked = ck; arg_listbox arg{*this, ck}; ess_->lister.wd_ptr()->events().checked.emit(arg); + ess_->update(); } return *this; } @@ -3539,6 +3540,7 @@ namespace nana else if (ess_->lister.last_selected_abs == pos_) ess_->lister.last_selected_abs.set_both(npos); + ess_->update(); return *this; }