From 830839ae27f71f3d20cccccf2625d435aeeac844 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 28 Sep 2016 07:47:53 +0800 Subject: [PATCH 01/16] add place::div() to return the div text introduce keywords 'undisplayed' and 'invisible' into div-text --- include/nana/gui/place.hpp | 3 +- source/gui/place.cpp | 159 ++++++++++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index dbc12111..176c7bd4 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -112,7 +112,8 @@ namespace nana void bind(window handle); window window_handle() const; - void div(const char* s); ///< Divides the attached widget into fields. + void div(const char* s); ///< Divides the attached widget into fields. + const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. field_reference field(const char* name);///< Returns a field with the specified name. diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 1af71f0c..739b80cf 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -56,7 +56,7 @@ namespace nana { div_start, div_end, splitter, identifier, dock, vert, grid, number, array, reparray, - weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, + weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible, collapse, parameters, equal, eof, error @@ -275,7 +275,7 @@ namespace nana _m_throw_error("a parameter list is required after 'collapse'"); return token::collapse; } - else if ("left" == idstr_ || "right" == idstr_ || "top" == idstr_ || "bottom" == idstr_) + else if ("left" == idstr_ || "right" == idstr_ || "top" == idstr_ || "bottom" == idstr_ || "undisplayed" == idstr_ || "invisible" == idstr_) { switch (idstr_.front()) { @@ -283,8 +283,11 @@ namespace nana case 'r': return token::right; case 't': return token::top; case 'b': return token::bottom; + case 'u': return token::undisplayed; + case 'i': return token::invisible; } } + return token::identifier; } @@ -442,6 +445,8 @@ namespace nana window window_handle{nullptr}; event_handle event_size_handle{nullptr}; + + std::string div_text; std::unique_ptr root_division; std::map fields; std::map docks; @@ -2147,6 +2152,9 @@ namespace nana std::vector> children; ::nana::direction div_dir = ::nana::direction::west; + bool undisplayed = false; + bool invisible = false; + for (token tk = tknizer.read(); tk != token::eof; tk = tknizer.read()) { bool exit_for = false; @@ -2305,6 +2313,10 @@ namespace nana div_dir = ::nana::direction::north; break; case token::bottom: div_dir = ::nana::direction::south; break; + case token::undisplayed: + undisplayed = true; break; + case token::invisible: + invisible = true; break; default: break; } if (exit_for) @@ -2430,6 +2442,9 @@ namespace nana div->children.swap(children); div->margin = std::move(margin); div->dir = div_dir; + + div->display = !undisplayed; + div->visible = !(undisplayed || invisible); return div; } @@ -2593,6 +2608,7 @@ namespace nana impl_->connect(div.get()); impl_->root_division.reset(); //clear atachments div-fields impl_->root_division.swap(div); + impl_->div_text.assign(s); } catch (...) { @@ -2601,6 +2617,11 @@ namespace nana } } + const std::string& place::div() const noexcept + { + return impl_->div_text; + } + void place::modify(const char* name, const char* div_text) { if (nullptr == div_text) @@ -2698,6 +2719,133 @@ namespace nana return *p; } + bool is_idchar(int ch) + { + return ('_' == ch || isalpha(ch) || isalnum(ch)); + } + + std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0) + { + const auto len = std::strlen(idstr); + auto pos = text.find(idstr, off); + if (text.npos == pos) + return text.npos; + + if (pos && is_idchar(text[pos - 1])) + return text.npos; + + if ((pos + len < text.length()) && is_idchar(text[pos + len])) + return text.npos; + + return pos; + } + + void update_div(std::string& div, const char* field, const char* attr, bool insertion) + { + const auto fieldname_pos = find_idstr(div, field); + if (div.npos == fieldname_pos) + return; + + //Get the bounds of this field + std::size_t begin = 0, end = 0; + + //Find the begin + int level = 0; + std::size_t pos = fieldname_pos; + while (true) + { + pos = div.find_last_of("<>", pos); + if (div.npos == pos) + return; + + if ('<' == div[pos]) + { + if (0 == level) + { + begin = pos; + break; + } + else + --level; + } + else + ++level; + } + + //Find the end + level = 0; + pos = fieldname_pos; + while (true) + { + pos = div.find_first_of("<>", pos); + if (div.npos == pos) + return; + + if ('>' == div[pos]) + { + if (0 == level) + { + end = pos + 1; + break; + } + else + --level; + } + else + ++level; + } + + auto fieldstr = div.substr(begin + 1, end - begin - 2); + + //Search the attribute + for (pos = 0; true; ++pos) + { + pos = find_idstr(fieldstr, attr, pos); + if (fieldstr.npos == pos) + break; + + //Check if the attr is belong to this field. + level = 0; + std::size_t off = pos; + while (true) + { + off = fieldstr.find_last_of("<>", off); + if (fieldstr.npos == off) + break; + + if ('>' == fieldstr[off]) + ++level; + else + --level; + + if (0 == off) + break; + --off; + } + + if (0 == level) + break; + } + + if (fieldstr.npos == pos) + { + //There is not an attribute + if (insertion) + div.insert(fieldname_pos + std::strlen(field), " " + std::string(attr)); + } + else + { + //There is an attribute + if (!insertion) + { + div.erase(begin + pos + 1, std::strlen(attr)); + + if ((div[begin + pos] == div[begin + pos + 1]) && (' ' == div[begin + pos])) + div.erase(begin + pos, 1); + } + } + } + void place::field_visible(const char* name, bool vsb) { if (!name) name = ""; @@ -2707,7 +2855,10 @@ namespace nana auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) + { div->set_visible(vsb); + update_div(impl_->div_text, name, "invisible", !vsb); + } } bool place::field_visible(const char* name) const @@ -2730,7 +2881,11 @@ namespace nana auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) + { + update_div(impl_->div_text, name, "invisible", false); + update_div(impl_->div_text, name, "undisplayed", !dsp); div->set_display(dsp); + } } bool place::field_display(const char* name) const From 3c2b36ead8857ad43caab68e7401adbef14e2ab2 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Thu, 29 Sep 2016 13:54:12 +0200 Subject: [PATCH 02/16] place::modify() now correctly updates the place::div_text. --- include/nana/gui/place.hpp | 302 +- source/gui/place.cpp | 6020 ++++++++++++++++++------------------ 2 files changed, 3166 insertions(+), 3156 deletions(-) diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 176c7bd4..f6359236 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -1,151 +1,151 @@ -/* - * An Implementation of Place for Layout - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 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/gui/place.cpp - * - * @contributions: - * min/max and splitter bar initial weight by Ariel Vina-Rodriguez. - */ - -#ifndef NANA_GUI_PLACE_HPP -#define NANA_GUI_PLACE_HPP -#include -#include -#include -#include - -namespace nana -{ - class widget; - namespace detail - { - class place_agent - { - public: - virtual ~place_agent() = default; - virtual std::unique_ptr create(nana::window) const = 0; - }; - } - - template - class agent - : public detail::place_agent - { - public: - agent(std::function initializer) - : init_(std::move(initializer)) - {} - - agent(const char* text) - : text_(text) - { - throw_not_utf8(text); - } - - agent(std::string text, std::function initializer = {}) - : text_(std::move(text)), init_(std::move(initializer)) - { - throw_not_utf8(text_); - } - - private: - std::unique_ptr create(nana::window handle) const override - { - std::unique_ptr ptr(new Widget(handle)); - ptr->caption(text_); - if (init_) - init_(*ptr); - return std::move(ptr); - } - private: - std::string text_; - std::function init_; - }; - - /// Layout managment - an object of class place is attached to a widget, and it automatically positions and resizes the children widgets. - class place - : ::nana::noncopyable - { - struct implement; - - class field_interface - { - field_interface(const field_interface&) = delete; - field_interface& operator=(const field_interface&) = delete; - field_interface(field_interface&&) = delete; - field_interface& operator=(field_interface&&) = delete; - public: - field_interface() = default; - virtual ~field_interface() = default; - virtual field_interface& operator<<(const char* label) = 0; - virtual field_interface& operator<<(std::string label) = 0; - virtual field_interface& operator<<(window) = 0; - virtual field_interface& fasten(window) = 0; - - template - field_interface& operator<<(const agent& ag) - { - _m_add_agent(ag); - return *this; - } - private: - virtual void _m_add_agent(const detail::place_agent&) = 0; - }; - public: - /// reference to a field manipulator which refers to a field object created by place - using field_reference = field_interface &; - - place(); - place(window);///< Attaches to a specified widget. - ~place(); - - /** @brief Bind to a window - * @param handle A handle to a window which the place wants to attach. - * @remark It will throw an exception if the place has already binded to a window. - */ - void bind(window handle); - window window_handle() const; - - void div(const char* s); ///< Divides the attached widget into fields. - const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. - void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. - - field_reference field(const char* name);///< Returns a field with the specified name. - - void field_visible(const char* field_name, bool visible); ///< - place& dock(const std::string& dockname, const std::string& factory_name, Args&& ... args) - { - return dock(dockname, factory_name, std::bind([](window parent, Args & ... args) - { - return std::unique_ptr(new Panel(parent, std::forward(args)...)); - }, std::placeholders::_1, args...)); - } - - place& dock(const std::string& dockname, std::string factory_name, std::function(window)> factory); - widget* dock_create(const std::string& factory); - private: - implement * impl_; - }; -}//end namespace nana -#include - -#endif //#ifndef NANA_GUI_PLACE_HPP +/* + * An Implementation of Place for Layout + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 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/gui/place.cpp + * + * @contributions: + * min/max and splitter bar initial weight by Ariel Vina-Rodriguez. + */ + +#ifndef NANA_GUI_PLACE_HPP +#define NANA_GUI_PLACE_HPP +#include +#include +#include +#include + +namespace nana +{ + class widget; + namespace detail + { + class place_agent + { + public: + virtual ~place_agent() = default; + virtual std::unique_ptr create(nana::window) const = 0; + }; + } + + template + class agent + : public detail::place_agent + { + public: + agent(std::function initializer) + : init_(std::move(initializer)) + {} + + agent(const char* text) + : text_(text) + { + throw_not_utf8(text); + } + + agent(std::string text, std::function initializer = {}) + : text_(std::move(text)), init_(std::move(initializer)) + { + throw_not_utf8(text_); + } + + private: + std::unique_ptr create(nana::window handle) const override + { + std::unique_ptr ptr(new Widget(handle)); + ptr->caption(text_); + if (init_) + init_(*ptr); + return std::move(ptr); + } + private: + std::string text_; + std::function init_; + }; + + /// Layout managment - an object of class place is attached to a widget, and it automatically positions and resizes the children widgets. + class place + : ::nana::noncopyable + { + struct implement; + + class field_interface + { + field_interface(const field_interface&) = delete; + field_interface& operator=(const field_interface&) = delete; + field_interface(field_interface&&) = delete; + field_interface& operator=(field_interface&&) = delete; + public: + field_interface() = default; + virtual ~field_interface() = default; + virtual field_interface& operator<<(const char* label) = 0; + virtual field_interface& operator<<(std::string label) = 0; + virtual field_interface& operator<<(window) = 0; + virtual field_interface& fasten(window) = 0; + + template + field_interface& operator<<(const agent& ag) + { + _m_add_agent(ag); + return *this; + } + private: + virtual void _m_add_agent(const detail::place_agent&) = 0; + }; + public: + /// reference to a field manipulator which refers to a field object created by place + using field_reference = field_interface &; + + place(); + place(window);///< Attaches to a specified widget. + ~place(); + + /** @brief Bind to a window + * @param handle A handle to a window which the place wants to attach. + * @remark It will throw an exception if the place has already binded to a window. + */ + void bind(window handle); + window window_handle() const; + + void div(const char* s); ///< Divides the attached widget into fields. + const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. + void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. + + field_reference field(const char* name);///< Returns a field with the specified name. + + void field_visible(const char* field_name, bool visible) const; ///< + place& dock(const std::string& dockname, const std::string& factory_name, Args&& ... args) + { + return dock(dockname, factory_name, std::bind([](window parent, Args & ... args) + { + return std::unique_ptr(new Panel(parent, std::forward(args)...)); + }, std::placeholders::_1, args...)); + } + + place& dock(const std::string& dockname, std::string factory_name, std::function(window)> factory); + widget* dock_create(const std::string& factory); + private: + implement * impl_; + }; +}//end namespace nana +#include + +#endif //#ifndef NANA_GUI_PLACE_HPP diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 739b80cf..77f89ba2 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -1,3005 +1,3015 @@ -/* - * An Implementation of Place for Layout - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 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/gui/place.cpp - * @contributors: Ariel Vina-Rodriguez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include //numeric_limits -#include //std::abs -#include //std::memset - -#include "place_parts.hpp" - -namespace nana -{ - namespace place_parts - { - //check the name - void check_field_name(const char* name) - { - if (*name && (*name != '_' && !(('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z')))) - throw std::invalid_argument("nana.place: bad field name"); - } - }//end namespace place_parts - - typedef place_parts::number_t number_t; - typedef place_parts::repeated_array repeated_array; - - namespace place_parts - { - class tokenizer - { - public: - enum class token - { - div_start, div_end, splitter, - identifier, dock, vert, grid, number, array, reparray, - weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible, - collapse, parameters, - equal, - eof, error - }; - - tokenizer(const char* p) - : divstr_(p), sp_(p) - {} - - const std::string& idstr() const - { - return idstr_; - } - - number_t number() const - { - return number_; - } - - std::vector& array() - { - return array_; - } - - repeated_array&& reparray() - { - return std::move(reparray_); - } - - std::vector& parameters() - { - return parameters_; - } - - std::size_t pos() const - { - return (sp_ - divstr_); - } - - std::string pos_str() const - { - return std::to_string(pos()); - } - - token read() - { - sp_ = _m_eat_whitespace(sp_); - - std::size_t readbytes = 0; - switch (*sp_) - { - case '\0': - return token::eof; - case '|': - ++sp_; - readbytes = _m_number(sp_, false); - sp_ += readbytes; - return token::splitter; - case '=': - ++sp_; - return token::equal; - case '<': - ++sp_; - return token::div_start; - case '>': - ++sp_; - return token::div_end; - case '[': - array_.clear(); - sp_ = _m_eat_whitespace(sp_ + 1); - if (*sp_ == ']') - { - ++sp_; - return token::array; - } - else - { - //When search the repeated. - bool repeated = false; - - while (true) - { - sp_ = _m_eat_whitespace(sp_); - auto tk = read(); - if (token::number != tk && token::variable != tk && token::repeated != tk) - _m_throw_error("invalid array element"); - - if (!repeated) - { - switch (tk) - { - case token::number: - array_.push_back(number_); - break; - case token::variable: - array_.push_back({}); - break; - default: - repeated = true; - reparray_.repeated(); - reparray_.assign(std::move(array_)); - } - } - - sp_ = _m_eat_whitespace(sp_); - char ch = *sp_++; - - if (ch == ']') - return (repeated ? token::reparray : token::array); - - if (ch != ',') - _m_throw_error("invalid array"); - } - } - break; - case '(': - parameters_.clear(); - sp_ = _m_eat_whitespace(sp_ + 1); - if (*sp_ == ')') - { - ++sp_; - return token::parameters; - } - - while (true) - { - if (token::number == read()) - parameters_.push_back(number_); - else - _m_throw_error("invalid parameter."); - - sp_ = _m_eat_whitespace(sp_); - char ch = *sp_++; - - if (ch == ')') - return token::parameters; - - if (ch != ',') - _m_throw_error("invalid parameter."); - } - break; - case '.': case '-': - if (*sp_ == '-') - { - readbytes = _m_number(sp_ + 1, true); - if (readbytes) - ++readbytes; - } - else - readbytes = _m_number(sp_, false); - - if (readbytes) - { - sp_ += readbytes; - return token::number; - } - else - _m_throw_error("invalid character '" + std::string(1, *sp_) + "'"); - break; - default: - if ('0' <= *sp_ && *sp_ <= '9') - { - readbytes = _m_number(sp_, false); - if (readbytes) - { - sp_ += readbytes; - return token::number; - } - } - break; - } - - if ('_' == *sp_ || isalpha(*sp_)) - { - const char * idstart = sp_++; - - while ('_' == *sp_ || isalpha(*sp_) || isalnum(*sp_)) - ++sp_; - - idstr_.assign(idstart, sp_); - - if ("weight" == idstr_ || "min" == idstr_ || "max" == idstr_) - { - auto ch = idstr_[1]; - _m_attr_number_value(); - switch (ch) - { - case 'e': return token::weight; - case 'i': return token::min_px; - case 'a': return token::max_px; - } - } - else if ("dock" == idstr_) - return token::dock; - else if ("vertical" == idstr_ || "vert" == idstr_) - return token::vert; - else if ("variable" == idstr_ || "repeated" == idstr_) - return ('v' == idstr_[0] ? token::variable : token::repeated); - else if ("arrange" == idstr_ || "gap" == idstr_) - { - auto ch = idstr_[0]; - _m_attr_reparray(); - return ('a' == ch ? token::arrange : token::gap); - } - else if ("grid" == idstr_ || "margin" == idstr_) - { - auto idstr = idstr_; - if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr + "'"); - - return ('g' == idstr[0] ? token::grid : token::margin); - } - else if ("collapse" == idstr_) - { - if (token::parameters != read()) - _m_throw_error("a parameter list is required after 'collapse'"); - return token::collapse; - } - else if ("left" == idstr_ || "right" == idstr_ || "top" == idstr_ || "bottom" == idstr_ || "undisplayed" == idstr_ || "invisible" == idstr_) - { - switch (idstr_.front()) - { - case 'l': return token::left; - case 'r': return token::right; - case 't': return token::top; - case 'b': return token::bottom; - case 'u': return token::undisplayed; - case 'i': return token::invisible; - } - } - - return token::identifier; - } - - std::string err = "an invalid character '"; - err += *sp_; - err += "'"; - - _m_throw_error(err); - return token::error; //Useless, just for syntax correction. - } - private: - void _m_throw_error(char err_char) - { - std::string str = "place: invalid character '"; - str += err_char; - str += '\''; - _m_throw_error(str); - } - - void _m_throw_error(const std::string& err) - { - throw std::runtime_error("nana::place: " + err + " at " + std::to_string(static_cast(sp_ - divstr_))); - } - - void _m_attr_number_value() - { - if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr_ + "'"); - - auto p = _m_eat_whitespace(sp_); - - auto neg_ptr = p; - if ('-' == *p) - ++p; - - auto len = _m_number(p, neg_ptr != p); - if (0 == len) - _m_throw_error("the '" + idstr_ + "' requires a number(integer or real or percent)"); - - sp_ += len + (p - sp_); - } - - void _m_attr_reparray() - { - auto idstr = idstr_; - if (token::equal != read()) - _m_throw_error("an equal sign is required after '" + idstr + "'"); - - sp_ = _m_eat_whitespace(sp_); - - reparray_.reset(); - auto tk = read(); - switch (tk) - { - case token::number: - reparray_.push(number()); - reparray_.repeated(); - break; - case token::array: - reparray_.assign(std::move(array_)); - break; - case token::reparray: - break; - default: - _m_throw_error("a (repeated) array is required after '" + idstr + "'"); - } - } - - static const char* _m_eat_whitespace(const char* sp) - { - while (*sp && !isgraph(*sp)) - ++sp; - return sp; - } - - std::size_t _m_number(const char* sp, bool negative) - { - const char* allstart = sp; - sp = _m_eat_whitespace(sp); - - number_.assign(0); - - bool gotcha = false; - int integer = 0; - double real = 0; - //read the integral part. - const char* istart = sp; - while ('0' <= *sp && *sp <= '9') - { - integer = integer * 10 + (*sp - '0'); - ++sp; - } - const char* iend = sp; - - if ('.' == *sp) - { - double div = 1; - const char* rstart = ++sp; - while ('0' <= *sp && *sp <= '9') - { - real += (*sp - '0') / (div *= 10); - ++sp; - } - - if (rstart != sp) - { - real += integer; - number_.assign(negative ? -real : real); - gotcha = true; - } - } - else if (istart != iend) - { - number_.assign(negative ? -integer : integer); - gotcha = true; - } - - if (gotcha) - { - sp = _m_eat_whitespace(sp); - if ('%' == *sp) - { - if (number_t::kind::integer == number_.kind_of()) - number_.assign_percent(number_.integer()); - return sp - allstart + 1; - } - return sp - allstart; - } - number_.reset(); - return 0; - } - private: - const char* divstr_; - const char* sp_; - std::string idstr_; - number_t number_; - std::vector array_; - repeated_array reparray_; - std::vector parameters_; - }; //end class tokenizer - } - - //struct implement - struct place::implement - { - class field_gather; - class field_dock; - - class division; - class div_arrange; - class div_grid; - class div_splitter; - class div_dock; - class div_dockpane; - - window window_handle{nullptr}; - event_handle event_size_handle{nullptr}; - - std::string div_text; - std::unique_ptr root_division; - std::map fields; - std::map docks; - std::map dock_factoris; - - //A temporary pointer used to refer to a specified div object which - //will be deleted in modification process. - std::unique_ptr tmp_replaced; - - //The following functions are defined behind the definition of class division. - //because the class division here is an incomplete type. - ~implement(); - - void collocate(); - - static division * search_div_name(division* start, const std::string&); - std::unique_ptr scan_div(place_parts::tokenizer&); - void check_unique(const division*) const; - - //connect the field/dock with div object - void connect(division* start); - void disconnect(); - }; //end struct implement - - class place::implement::field_gather - : public place::field_interface - { - public: - struct element_t - { - window handle; - event_handle evt_destroy; - - element_t(window h, event_handle event_destroy) - :handle(h), evt_destroy(event_destroy) - {} - }; - - field_gather(place * p) - : place_ptr_(p) - {} - - ~field_gather() - { - for (auto & e : elements) - API::umake_event(e.evt_destroy); - - for (auto & e : fastened) - API::umake_event(e.evt_destroy); - } - - void visible(bool vsb) - { - for (auto & e : elements) - API::show_window(e.handle, vsb); - - for (auto & e : fastened) - API::show_window(e.handle, vsb); - } - - static event_handle erase_element(std::vector& elements, window handle) - { - for (auto i = elements.begin(); i != elements.end(); ++i) - { - if (i->handle == handle) - { - auto evt_destroy = i->evt_destroy; - elements.erase(i); - return evt_destroy; - } - } - return nullptr; - } - private: - //Listen to destroy of a window - //It will delete the element and recollocate when the window destroyed. - event_handle _m_make_destroy(window wd) - { - return API::events(wd).destroy.connect([this, wd](const arg_destroy&) - { - if (erase_element(elements, wd)) - { - if (!API::is_destroying(API::get_parent_window(wd))) - place_ptr_->collocate(); - } - }); - } - - field_interface& operator<<(const char* label_text) override - { - return static_cast(this)->operator<<(agent