diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 1efb516f..b5f92f56 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -19,11 +19,8 @@ #include #include - -#include #include - namespace nana { /// move to *.h ?? diff --git a/include/nana/gui/detail/widget_content_measurer_interface.hpp b/include/nana/gui/detail/widget_content_measurer_interface.hpp index d78f932e..4f175493 100644 --- a/include/nana/gui/detail/widget_content_measurer_interface.hpp +++ b/include/nana/gui/detail/widget_content_measurer_interface.hpp @@ -30,11 +30,18 @@ namespace nana /// Measures content /** - * @param limit_width true if limits the width, false if limits the height. - * @param limit_pixels the number of pixels of the limited edge. If this parameter is zero, it is ignored - * @return the size of content - */ - virtual optional measure(graph_reference, bool limit_width, unsigned limit_pixels) const = 0; + * @param graph The graphics for the operation. + * @param limit_pixels The number of pixels of the limited edge. If this parameter is zero, it is ignored. + * @param limit_width True if limits the width, false if limits the height. + * @return the size of content. + */ + virtual optional measure(graph_reference graph, unsigned limit_pixels, bool limit_width) const = 0; + + /// Returns the extension to the size of widget from content extent + /** + * @return the width and height of extension to the widget size. + */ + virtual size extension() const = 0; }; } } diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 1b3e6e9d..fe571076 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -403,6 +403,17 @@ namespace API bool ignore_mouse_focus(window); ///< Determines whether the mouse focus is enabled void at_safe_place(window, std::function); + + /// Returns a widget content extent size + /** + * @param wd A handle to a window that returns its content extent size. + * @param limited_px Specifies the max pixels of width or height. If this parameter is zero, this parameter will be ignored. + * @param limit_width Indicates whether the it limits the width or height. If this parameter is *true*, the width is limited. + * If the parameter is *false*, the height is limited. This parameter is ignored if limited_px = 0. + * @return if optional has a value, the first size indicates the content extent, the second size indicates the size of + * widget by the content extent. + */ + optional> content_extent(window wd, unsigned limited_px, bool limit_width); }//end namespace API }//end namespace nana diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp index c0109e2c..d68c0d7c 100644 --- a/include/nana/gui/widgets/button.hpp +++ b/include/nana/gui/widgets/button.hpp @@ -59,6 +59,8 @@ namespace nana{ element::cite_bground cite_{"button"}; + std::unique_ptr measurer_; + struct attr_tag { element_state e_state; diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 9ba982a8..861ea512 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -298,19 +298,10 @@ namespace nana 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_))); @@ -362,12 +353,12 @@ namespace nana static const char* _m_eat_whitespace(const char* sp) noexcept { - while (*sp && !isgraph(*sp)) + while (*sp && !std::isgraph(*sp)) ++sp; return sp; } - std::size_t _m_number(const char* sp, bool negative) + std::size_t _m_number(const char* sp, bool negative) noexcept { const char* allstart = sp; sp = _m_eat_whitespace(sp); @@ -412,23 +403,22 @@ namespace nana if (gotcha) { sp = _m_eat_whitespace(sp); - if ('%' == *sp) + if ('%' != *sp) + return sp - allstart; + + switch (number_.kind_of()) { - switch (number_.kind_of()) - { - case number_t::kind::integer: - number_.assign_percent(number_.integer()); - break; - case number_t::kind::real: - number_.assign_percent(number_.real()); - break; - default: - break; - } - - return sp - allstart + 1; + case number_t::kind::integer: + number_.assign_percent(number_.integer()); + break; + case number_t::kind::real: + number_.assign_percent(number_.real()); + break; + default: + break; } - return sp - allstart; + + return sp - allstart + 1; } number_.reset(); return 0; @@ -445,12 +435,12 @@ namespace nana } - inline bool is_idchar(int ch) noexcept + static bool is_idchar(int ch) noexcept { return ('_' == ch || std::isalnum(ch)); } - std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0) + static std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0) { const auto len = std::strlen(idstr); @@ -468,7 +458,65 @@ namespace nana return text.npos; } - std::pair get_field_bound(const std::string& div, const char* idstr, int depth) + //Find the text bound of a field. The parameter start_pos is one of bound characters of the field whose bound will be returned + static std::pair get_field_bound(const std::string& div, std::size_t start_pos) + { + int depth = 0; + if ('<' == div[start_pos]) + { + auto off = start_pos + 1; + while (off < div.length()) + { + auto pos = div.find_first_of("<>", off); + if (div.npos == pos) + break; + + if ('<' == div[pos]) + { + ++depth; + off = pos + 1; + continue; + } + + if (0 == depth) + return{ start_pos, pos + 1 }; + + --depth; + off = pos + 1; + } + } + else if (('>' == div[start_pos]) && (start_pos > 0)) + { + auto off = start_pos - 1; + while (true) + { + auto pos = div.find_last_of("<>", off); + if (div.npos == pos) + break; + + if ('>' == div[pos]) + { + ++depth; + if (0 == pos) + break; + + off = pos - 1; + } + + if (0 == depth) + return{ pos, start_pos + 1 }; + + if (0 == pos) + break; + + off = pos - 1; + } + } + + return{}; + } + + static std::pair get_field_bound(const std::string& div, const char* idstr, int depth) { auto start_pos = find_idstr(div, idstr); @@ -498,28 +546,7 @@ namespace nana start_pos = pos - 1; } - auto off = start_pos + 1; - - while (true) - { - auto pos = div.find_first_of("<>", off); - - if (div.npos == pos) - return{}; - - if ('<' == div[pos]) - { - ++depth; - off = pos + 1; - continue; - } - - if (0 == depth) - return{ start_pos, pos + 1 }; - - --depth; - off = pos + 1; - } + return get_field_bound(div, start_pos + 1); } //struct implement @@ -554,13 +581,13 @@ namespace nana void collocate(); - static division * search_div_name(division* start, const std::string&); + static division * search_div_name(division* start, const std::string&) noexcept; 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(); + void disconnect() noexcept; }; //end struct implement class place::implement::field_gather @@ -572,16 +599,16 @@ namespace nana window handle; event_handle evt_destroy; - element_t(window h, event_handle event_destroy) + element_t(window h, event_handle event_destroy) noexcept :handle(h), evt_destroy(event_destroy) {} }; - field_gather(place * p) + field_gather(place * p) noexcept : place_ptr_(p) {} - ~field_gather() + ~field_gather() noexcept { for (auto & e : elements) API::umake_event(e.evt_destroy); @@ -599,7 +626,7 @@ namespace nana API::show_window(e.handle, vsb); } - static event_handle erase_element(std::vector& elements, window handle) + static event_handle erase_element(std::vector& elements, window handle) noexcept { for (auto i = elements.begin(); i != elements.end(); ++i) { @@ -710,6 +737,28 @@ namespace nana field->attached = nullptr; } + static unsigned calc_number(const place_parts::number_t& number, unsigned area_px, double adjustable_px, double& precise_px) + { + switch (number.kind_of()) + { + case number_t::kind::integer: + return static_cast(number.integer()); + case number_t::kind::real: + return static_cast(number.real()); + case number_t::kind::percent: + adjustable_px = area_px * number.real(); + case number_t::kind::none: + { + auto fpx = adjustable_px + precise_px; + auto px = static_cast(fpx); + precise_px = fpx - px; + return px; + } + break; + } + return 0; //Useless + } + std::pair calc_weight_floor() { std::pair floor; @@ -751,7 +800,62 @@ namespace nana fv = this->weight.real(); } else + { + if (this->fit_content) + { + std::size_t fit_count = 0; + unsigned max_value = 0; + for (auto & elm : this->field->elements) + { + auto extent = API::content_extent(elm.handle, 0, false); + if (extent) + { + ++fit_count; + if (vert) + { + floor.second += extent->second.height; + if (extent->second.width > max_value) + max_value = extent->second.width; + } + else + { + floor.first += extent->second.width; + if (extent->second.height > max_value) + max_value = extent->second.height; + } + } + } + + if (max_value) + { + if (vert) + floor.first = max_value; + else + floor.second = max_value; + } + + if (fit_count > 1) + { + double percent = 0; + for (std::size_t i = 0; i < fit_count - 1; ++i) + { + auto gap_value = gap.at(i); + if (gap_value.kind_of() == number_t::kind::percent) + { + percent += gap_value.real(); + } + else + { + double precise_px = 0; + fv += calc_number(gap_value, 100, 0, precise_px); + } + } + + fv *= (1 + percent); + } + } run_.weight_floor = floor; + } } return floor; @@ -831,7 +935,7 @@ namespace nana return (div == last); } - static double limit_px(const division* div, double px, unsigned area_px) + static double limit_px(const division* div, double px, unsigned area_px) noexcept { auto const vert = (div->div_owner && (div->div_owner->kind_of_division == kind::vertical_arrange)); @@ -885,7 +989,7 @@ namespace nana return nullptr; } public: - void _m_visible_for_child(division * div, bool vsb) + static void _m_visible_for_child(division * div, bool vsb) noexcept { for (auto & child : div->children) { @@ -1002,13 +1106,43 @@ namespace nana for (auto & el : field->elements) { element_r.x_ref() = static_cast(position); - auto px = _m_calc_number(arrange_.at(index), area_px, adjustable_px, precise_px); - element_r.w_ref() = px; - API::move_window(el.handle, element_r.result()); + bool moved = false; + unsigned px = 0; + if (this->fit_content) + { + auto extent = API::content_extent(el.handle, 0, false); + if (extent) + { + auto r = element_r.result(); + r.dimension(extent->second); + + if (vert) + { + if (area_margined.width > r.width) + r.x += (area_margined.width - r.width) / 2; + } + else + { + if (area_margined.height > r.height) + r.y += (area_margined.height - r.height) / 2; + } + + API::move_window(el.handle, r); + px = (vert ? r.height : r.width); + moved = true; + } + } + + if (!moved) + { + px = calc_number(arrange_.at(index), area_px, adjustable_px, precise_px); + element_r.w_ref() = px; + API::move_window(el.handle, element_r.result()); + } if (index + 1 < field->elements.size()) - position += (px + _m_calc_number(gap.at(index), area_px, 0, precise_px)); + position += (px + calc_number(gap.at(index), area_px, 0, precise_px)); ++index; } @@ -1018,28 +1152,6 @@ namespace nana } } private: - static unsigned _m_calc_number(const place_parts::number_t& number, unsigned area_px, double adjustable_px, double& precise_px) - { - switch (number.kind_of()) - { - case number_t::kind::integer: - return static_cast(number.integer()); - case number_t::kind::real: - return static_cast(number.real()); - case number_t::kind::percent: - adjustable_px = area_px * number.real(); - case number_t::kind::none: - { - auto fpx = adjustable_px + precise_px; - auto px = static_cast(fpx); - precise_px = fpx - px; - return px; - } - break; - } - return 0; //Useless - } - static std::pair _m_calc_fa(const place_parts::number_t& number, unsigned area_px, double& precise_px) { std::pair result; @@ -1067,7 +1179,7 @@ namespace nana } //Returns the fixed pixels and the number of adjustable items. - std::pair _m_fixed_and_adjustable(kind match_kind, unsigned area_px) const + std::pair _m_fixed_and_adjustable(kind match_kind, unsigned area_px) const noexcept { std::pair result; if (field && (kind_of_division == match_kind)) @@ -1112,7 +1224,7 @@ namespace nana double max_px; }; - static double _m_find_lowest_revised_division(const std::vector& revises, double level_px) + static double _m_find_lowest_revised_division(const std::vector& revises, double level_px) noexcept { double v = (std::numeric_limits::max)(); @@ -1126,7 +1238,7 @@ namespace nana return v; } - static std::size_t _m_remove_revised(std::vector& revises, double value, std::size_t& full_count) + static std::size_t _m_remove_revised(std::vector& revises, double value, std::size_t& full_count) noexcept { full_count = 0; std::size_t reached_mins = 0; @@ -1148,7 +1260,7 @@ namespace nana return reached_mins; } - double _m_revise_adjustable(std::pair& fa, unsigned area_px) + double _m_revise_adjustable(std::pair& fa, unsigned area_px) noexcept { if (fa.first >= area_px || 0 == fa.second) return 0; @@ -1305,6 +1417,8 @@ namespace nana return; } + auto i = field->elements.cbegin(); + auto const end = field->elements.cend(); if (dimension.first <= 1 && dimension.second <= 1) { auto n_of_wd = field->elements.size(); @@ -1321,7 +1435,6 @@ namespace nana if ((edge * edge) < n_of_wd) ++edge; } - bool exit_for = false; double y = area.y; double block_w = area.width / double(edge); double block_h = area.height / double((n_of_wd / edge) + (n_of_wd % edge ? 1 : 0)); @@ -1329,19 +1442,12 @@ namespace nana unsigned uns_block_h = static_cast(block_h); unsigned height = (uns_block_h > gap_size ? uns_block_h - gap_size : uns_block_h); - auto i = field->elements.cbegin(), end = field->elements.cend(); std::size_t arr_pos = 0; - for (std::size_t u = 0; u < edge; ++u) + for (std::size_t u = 0; (u < edge && i != end); ++u) { double x = area.x; - for (std::size_t v = 0; v < edge; ++v) + for (std::size_t v = 0; (v < edge && i != end); ++v, ++i) { - if (i == end) - { - exit_for = true; - break; - } - unsigned value = 0; auto arr = arrange_.at(arr_pos++); @@ -1354,9 +1460,7 @@ namespace nana if (width > gap_size) width -= gap_size; API::move_window(i->handle, rectangle{ static_cast(x), static_cast(y), width, height }); x += block_w; - ++i; } - if (exit_for) break; y += block_h; } } @@ -1365,52 +1469,40 @@ namespace nana double block_w = int(area.width - gap_size * (dimension.first - 1)) / double(dimension.first); double block_h = int(area.height - gap_size * (dimension.second - 1)) / double(dimension.second); - std::unique_ptr table_ptr(new char[dimension.first * dimension.second]); - + std::unique_ptr table_ptr{ new char[dimension.first * dimension.second] }; char *table = table_ptr.get(); std::memset(table, 0, dimension.first * dimension.second); std::size_t lbp = 0; - bool exit_for = false; - - auto i = field->elements.cbegin(), end = field->elements.cend(); double precise_h = 0; - for (std::size_t c = 0; c < dimension.second; ++c) + for (std::size_t u = 0; (u < dimension.second && i != end); ++u) { - unsigned block_height_px = static_cast(block_h + precise_h); + auto const block_height_px = static_cast(block_h + precise_h); precise_h = (block_h + precise_h) - block_height_px; double precise_w = 0; - for (std::size_t l = 0; l < dimension.first; ++l) + for (std::size_t v = 0; (v < dimension.first && i != end); ++v) { - if (table[l + lbp]) + if (table[v + lbp]) { precise_w += block_w; - auto px = static_cast(precise_w); - precise_w -= px; + precise_w -= static_cast(precise_w); continue; } - if (i == end) - { - exit_for = true; - break; - } - std::pair room{ 1, 1 }; + _m_find_collapse(static_cast(v), static_cast(u), room); - _m_find_collapse(static_cast(l), static_cast(c), room); - - int pos_x = area.x + static_cast(l * (block_w + gap_size)); - int pos_y = area.y + static_cast(c * (block_h + gap_size)); + int pos_x = area.x + static_cast(v * (block_w + gap_size)); + int pos_y = area.y + static_cast(u * (block_h + gap_size)); unsigned result_h; if (room.first <= 1 && room.second <= 1) { precise_w += block_w; result_h = block_height_px; - table[l + lbp] = 1; + table[v + lbp] = 1; } else { @@ -1419,7 +1511,7 @@ namespace nana for (unsigned y = 0; y < room.second; ++y) for (unsigned x = 0; x < room.first; ++x) - table[l + x + lbp + y * dimension.first] = 1; + table[v + x + lbp + y * dimension.first] = 1; } unsigned result_w = static_cast(precise_w); @@ -1429,17 +1521,14 @@ namespace nana ++i; } - if (exit_for) - { - size empty_sz; - for (; i != end; ++i) - API::window_size(i->handle, empty_sz); - break; - } lbp += dimension.first; } } + // Empty the size of windows that are out range of grid + for (; i != end; ++i) + API::window_size(i->handle, size{}); + for (auto & fsn : field->fastened) API::move_window(fsn.handle, area); } @@ -1551,27 +1640,13 @@ namespace nana int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x); const auto total_pixels = static_cast(left_pixels_ + right_pixels_); -/* - auto left_px = static_cast(left_pixels_) + delta; //deprecated - if (left_px > total_pixels) - left_px = total_pixels; - else if (left_px < 0) - left_px = 0; -*/ + auto left_px = std::clamp(static_cast(left_pixels_) + delta, 0, total_pixels); double imd_rate = 100.0 / area_px; left_px = static_cast(limit_px(_m_leaf_left(), left_px, area_px)); _m_leaf_left()->weight.assign_percent(imd_rate * left_px); - /* - auto right_px = static_cast(right_pixels_) - delta; //deprecated - if (right_px > total_pixels) - right_px = total_pixels; - else if (right_px < 0) - right_px = 0; - */ - auto right_px = std::clamp(static_cast(right_pixels_) - delta, 0, total_pixels); right_px = static_cast(limit_px(_m_leaf_right(), right_px, area_px)); @@ -1607,18 +1682,9 @@ namespace nana auto area_px = right.right() - left.x(); auto right_px = static_cast(limit_px(leaf_right, init_weight_.get_value(area_px), static_cast(area_px))); - /* //deprecated - auto pos = area_px - right_px - splitter_px; //New position of splitter - if (pos < limited_range.x()) - pos = limited_range.x(); - else if (pos > limited_range.right()) - pos = limited_range.right(); - */ - //New position of splitter const auto pos = std::clamp(static_cast(area_px - right_px - splitter_px), limited_range.x(), limited_range.right()); - rectangle_rotator sp_r(vert, field_area); sp_r.x_ref() = pos; @@ -1650,7 +1716,7 @@ namespace nana splitter_.move(this->field_area); } private: - static int _m_search_name(const division* div, std::string& name) + static int _m_search_name(const division* div, std::string& name) noexcept { if (div->name.size()) { @@ -1674,64 +1740,6 @@ namespace nana return -1; } - static std::pair _m_field_bound(const std::string& div, std::size_t start_pos) - { - int depth = 0; - - if ('<' == div[start_pos]) - { - auto off = start_pos + 1; - while (off < div.length()) - { - auto pos = div.find_first_of("<>", off); - if (div.npos == pos) - break; - - if ('<' == div[pos]) - { - ++depth; - off = pos + 1; - continue; - } - - if (0 == depth) - return{ start_pos, pos + 1}; - - --depth; - off = pos + 1; - } - } - else if (('>' == div[start_pos]) && (start_pos > 0)) - { - auto off = start_pos - 1; - while (true) - { - auto pos = div.find_last_of("<>", off); - if (div.npos == pos) - break; - - if ('>' == div[pos]) - { - ++depth; - if (0 == pos) - break; - - off = pos - 1; - } - - if (0 == depth) - return{ pos, start_pos + 1}; - - if (0 == pos) - break; - - off = pos - 1; - } - } - - return{}; - } - static void _m_remove_attr(std::string& div, const char* attr) { auto attr_pos = div.find(attr); @@ -1820,25 +1828,11 @@ namespace nana auto fieldstr = div.substr(bound.first, bound.second - bound.first); _m_remove_attr(fieldstr, "weight"); - decltype(bound) other_bound; - if (left) - { - //Get the bound of leaf right - auto pos = div.find('<', bound.second + 1); - if (div.npos == pos) - throw std::runtime_error("please report an issue if it throws"); + std::string::size_type tag_pos{ left ? div.find('<', bound.second + 1) : div.rfind('>', bound.first - 1) }; + if (div.npos == tag_pos) + throw std::runtime_error("place report an issue if it throws"); - other_bound = _m_field_bound(div, pos); - } - else - { - //Get the bound of leaf left - auto pos = div.rfind('>', bound.first - 1); - if (div.npos == pos) - throw std::runtime_error("place report an issue if it throws"); - - other_bound = _m_field_bound(div, pos); - } + auto other_bound = get_field_bound(div, tag_pos); auto other_fieldstr = div.substr(other_bound.first, other_bound.second - other_bound.first); _m_remove_attr(other_fieldstr, "weight"); @@ -1905,26 +1899,10 @@ namespace nana endpos = left_base + static_cast(leaf_left->max_px.get_value(area.w())); if (!leaf_right->min_px.empty()) - { - /* - auto v = leaf_right->min_px.get_value(area.w()); //deprecated - auto x = right_base - static_cast(v); - if (x < endpos) - endpos = x; - */ - endpos = (std::min)(right_base - static_cast(leaf_right->min_px.get_value(area.w())), endpos); - } + if (!leaf_right->max_px.empty()) - { - /* - auto v = leaf_right->max_px.get_value(area.w()); //deprecated - auto x = right_base - static_cast(v); - if (x > pos) - pos = x; - */ pos = (std::max)(right_base - static_cast(leaf_right->max_px.get_value(area.w())), pos); - } area.x_ref() = pos; area.w_ref() = unsigned(endpos - pos + splitter_px); @@ -2275,7 +2253,7 @@ namespace nana : division(kind::dock, std::move(name)), impl_(impl) {} - division* front() const + division* front() const noexcept { for (auto & child : children) { @@ -2523,7 +2501,7 @@ namespace nana //search_div_name //search a division with the specified name. - place::implement::division * place::implement::search_div_name(division* start, const std::string& name) + place::implement::division * place::implement::search_div_name(division* start, const std::string& name) noexcept { if (start) { @@ -2540,6 +2518,20 @@ namespace nana return nullptr; } + static int get_parameter(place_parts::tokenizer& tknizer, std::size_t pos) + { + auto & arg = tknizer.parameters()[pos]; + //auto & arg = params[pos]; + + if (arg.kind_of() == number_t::kind::integer) + return arg.integer(); + else if (arg.kind_of() == number_t::kind::real) + return static_cast(arg.real()); + + const char* pos_strs[] = { "1st", "2nd", "3rd", "4th" }; + throw std::invalid_argument("nana.place: the type of the " + std::string{pos_strs[pos]} +"th parameter for collapse should be integer."); + } + auto place::implement::scan_div(place_parts::tokenizer& tknizer) -> std::unique_ptr { typedef place_parts::tokenizer::token token; @@ -2561,9 +2553,8 @@ namespace nana bool undisplayed = false; bool invisible = false; - for (token tk = tknizer.read(); tk != token::eof; tk = tknizer.read()) + for (token tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read()) { - bool exit_for = false; switch (tk) { case token::dock: @@ -2620,29 +2611,13 @@ namespace nana if (tknizer.parameters().size() != 4) throw std::invalid_argument("nana.place: collapse requires 4 parameters."); - auto get_number = [](const number_t & arg, const std::string& nth) - { - if (arg.kind_of() == number_t::kind::integer) - return arg.integer(); - else if (arg.kind_of() == number_t::kind::real) - return static_cast(arg.real()); - - throw std::invalid_argument("nana.place: the type of the "+ nth +" parameter for collapse should be integer."); + ::nana::rectangle col{ + get_parameter(tknizer, 0), + get_parameter(tknizer, 1), + static_cast(get_parameter(tknizer, 2)), + static_cast(get_parameter(tknizer, 3)) }; - ::nana::rectangle col; - auto arg = tknizer.parameters().at(0); - col.x = get_number(arg, "1st"); - - arg = tknizer.parameters().at(1); - col.y = get_number(arg, "2nd"); - - arg = tknizer.parameters().at(2); - col.width = static_cast(get_number(arg, "3rd")); - - arg = tknizer.parameters().at(3); - col.height = static_cast(get_number(arg, "4th")); - //Check the collapse area. //Ignore this collapse if its area is less than 2(col.width * col.height < 2) if (!col.empty() && (col.width > 1 || col.height > 1) && (col.x >= 0 && col.y >= 0)) @@ -2708,9 +2683,6 @@ namespace nana break; } break; - case token::div_end: - exit_for = true; - break; case token::identifier: name = tknizer.idstr(); break; @@ -2728,8 +2700,6 @@ namespace nana invisible = true; break; default: break; } - if (exit_for) - break; } field_gather * attached_field = nullptr; @@ -2791,19 +2761,6 @@ namespace nana max_px.reset(); } - /* - //The weight will be ignored if one of min and max is specified. //deprecated - if (min_px.empty() && max_px.empty()) - { - div->weight = weight; - } - else - { - div->min_px = min_px; - div->max_px = max_px; - } - */ - if (!min_px.empty()) div->min_px = min_px; @@ -2856,10 +2813,10 @@ namespace nana } division * next = nullptr; - for (auto i = adjusted_children.rbegin(); i != adjusted_children.rend(); ++i) + for (int i = static_cast(adjusted_children.size()) - 1; i >= 0; --i) { - i->get()->div_next = next; - next = i->get(); + adjusted_children[i]->div_next = next; + next = adjusted_children[i].get(); } children.swap(adjusted_children); @@ -2911,6 +2868,8 @@ namespace nana if (!start) return; + check_unique(start); //may throw if there is a redefined name of field. + this->disconnect(); std::map docks_to_be_closed; @@ -2976,7 +2935,7 @@ namespace nana } } - void place::implement::disconnect() + void place::implement::disconnect() noexcept { for (auto & fd : fields) { @@ -3033,8 +2992,7 @@ namespace nana auto div = impl_->scan_div(tknizer); try { - impl_->check_unique(div.get()); //may throw if there is a redefined name of field. - impl_->connect(div.get()); + impl_->connect(div.get()); //throws if there is a redefined name of field. impl_->root_division.reset(); //clear atachments div-fields impl_->root_division.swap(div); impl_->div_text.assign(s); @@ -3107,8 +3065,7 @@ namespace nana replaced->swap(modified); - impl_->check_unique(impl_->root_division.get()); - impl_->connect(impl_->root_division.get()); + impl_->connect(impl_->root_division.get()); //throws if there is a duplicate name impl_->tmp_replaced.reset(); update_div(impl_->div_text, name, div_text, update_operation::replace); @@ -3367,7 +3324,7 @@ namespace nana dock_ptr->dockarea->move(dock_ptr->attached->field_area); } - return dock_ptr->dockarea->add_pane(i->second->factories[factory]); + return dock_ptr->dockarea->add_pane(dock_ptr->factories[factory]); } return nullptr; diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 2bd29c1d..0be30e96 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -1,7 +1,7 @@ /* * Parts of Class Place * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -426,7 +426,7 @@ namespace nana value_.integer = 0; } - void reset() + void reset() noexcept { kind_ = kind::none; value_.integer = 0; @@ -447,17 +447,17 @@ namespace nana return false; } - bool empty() const throw() + bool empty() const noexcept { return (kind::none == kind_); } - kind kind_of() const + kind kind_of() const noexcept { return kind_; } - double get_value(int ref_percent) const + double get_value(int ref_percent) const noexcept { switch (kind_) { @@ -473,33 +473,33 @@ namespace nana return 0; } - int integer() const + int integer() const noexcept { if (kind::integer == kind_) return value_.integer; return static_cast(value_.real); } - double real() const + double real() const noexcept { if (kind::integer == kind_) return value_.integer; return value_.real; } - void assign(int i) + void assign(int i) noexcept { kind_ = kind::integer; value_.integer = i; } - void assign(double d) + void assign(double d) noexcept { kind_ = kind::real; value_.real = d; } - void assign_percent(double d) + void assign_percent(double d) noexcept { kind_ = kind::percent; value_.real = d / 100; diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index f2761988..10763d4b 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -1,7 +1,7 @@ /* * Nana GUI Programming Interface Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1439,5 +1439,29 @@ namespace API { restrict::wd_manager().set_safe_place(reinterpret_cast(wd), std::move(fn)); } + + optional> content_extent(window wd, unsigned limited_px, bool limit_width) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + + if (restrict::wd_manager().available(iwd) && iwd->annex.content_measurer) + { + paint::graphics* graph = &iwd->drawer.graphics; + paint::graphics temp_graph; + if (graph->empty()) + { + temp_graph.make({ 1, 1 }); + temp_graph.typeface(graph->typeface()); + graph = &temp_graph; + } + + auto extent = iwd->annex.content_measurer->measure(*graph, limited_px, limit_width); + if (extent) + return std::make_pair(extent.value(), extent.value() + iwd->annex.content_measurer->extension()); + } + + return{}; + } }//end namespace API }//end namespace nana diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 241d3a63..3e6090e1 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -1,7 +1,7 @@ /* * A Button Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -11,12 +11,40 @@ */ #include +#include + #include namespace nana{ namespace drawerbase { namespace button { + class trigger::measurer + : public dev::widget_content_measurer_interface + { + public: + measurer(trigger* t) + : trigger_{ t } + {} + + optional measure(graph_reference graph, unsigned limit_pixels, bool limit_width) const override + { + wchar_t shortkey; + std::string::size_type shortkey_pos; + + auto str = to_wstring(API::transform_shortkey_text(trigger_->wdg_->caption(), shortkey, &shortkey_pos)); + auto text_sz = graph.text_extent_size(str); + + return size{ text_sz.width, text_sz.height }; + } + + size extension() const override + { + return { 14, 10}; + } + private: + trigger * trigger_; + }; //trigger //@brief: draw the button @@ -26,6 +54,8 @@ namespace nana{ namespace drawerbase attr_.omitted = attr_.focused = attr_.pushed = attr_.enable_pushed = attr_.keep_pressed = false; attr_.focus_color = true; attr_.icon = nullptr; + + measurer_.reset(new measurer{this}); } trigger::~trigger() @@ -44,6 +74,7 @@ namespace nana{ namespace drawerbase API::tabstop(wd); API::effects_edge_nimbus(wd, effects::edge_nimbus::active); API::effects_edge_nimbus(wd, effects::edge_nimbus::over); + API::dev::set_measurer(widget, measurer_.get()); } bool trigger::enable_pushed(bool eb) @@ -251,17 +282,17 @@ namespace nana{ namespace drawerbase } else { - graph.palette(true, ::nana::color(colors::white)); + graph.palette(true, color{ colors::white }); if(attr_.omitted) { tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, true); - graph.palette(true, ::nana::color(colors::gray)); + graph.palette(true, color{ colors::gray }); tr.render(pos, txtptr, txtlen, omitted_pixels, true); } else { graph.bidi_string(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen); - graph.palette(true, ::nana::color(colors::gray)); + graph.palette(true, color{ colors::gray }); graph.bidi_string(pos, txtptr, txtlen); } } diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 115710e4..ea33dd33 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -655,14 +655,19 @@ namespace nana : impl_{ impl } {} - optional measure(bool limit_width, unsigned limit_pixels) const override + optional measure(graph_reference graph, unsigned limit_pixels, bool limit_width) const override { - if (impl_->graph) + if (graph) { } return{}; } + + size extension() const override + { + return{ 2, 2 }; + } private: implement * const impl_; };