diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 861ea512..2c6b54de 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -57,7 +56,7 @@ namespace nana enum class token { div_start, div_end, splitter, - identifier, dock, fit, vert, grid, number, array, reparray, + identifier, dock, fit, fit_s, vert, grid, number, array, reparray, weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible, collapse, parameters, equal, @@ -73,7 +72,7 @@ namespace nana return idstr_; } - number_t number() const + const number_t& number() const { return number_; } @@ -98,11 +97,6 @@ namespace nana return (sp_ - divstr_); } - std::string pos_str() const - { - return std::to_string(pos()); - } - token read() { sp_ = _m_eat_whitespace(sp_); @@ -255,6 +249,8 @@ namespace nana return token::dock; else if ("fit" == idstr_) return token::fit; + else if ("fit_s" == idstr_) + return token::fit_s; else if ("vertical" == idstr_ || "vert" == idstr_) return token::vert; else if ("variable" == idstr_ || "repeated" == idstr_) @@ -434,6 +430,16 @@ namespace nana }; //end class tokenizer } + static bool is_vert_dir(::nana::direction dir) + { + return (dir == ::nana::direction::north || dir == ::nana::direction::south); + } + + static int horz_point(bool vert, const point& pos) + { + return (vert ? pos.y : pos.x); + } + static bool is_idchar(int ch) noexcept { @@ -640,18 +646,31 @@ namespace nana 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) + void _m_insert_widget(window wd, bool to_fasten) { - return API::events(wd).destroy.connect([this, wd](const arg_destroy&) + if (API::empty_window(wd)) + throw std::invalid_argument("Place: An invalid window handle."); + + if (API::get_parent_window(wd) != place_ptr_->window_handle()) + throw std::invalid_argument("Place: the window is not a child of place bind window"); + + //Listen to destroy of a window + //It will delete the element and recollocate when the window destroyed. + auto evt = API::events(wd).destroy.connect([this, to_fasten](const arg_destroy& arg) { - if (erase_element(elements, wd)) + if (!to_fasten) { - if (!API::is_destroying(API::get_parent_window(wd))) - place_ptr_->collocate(); + if (erase_element(elements, arg.window_handle)) + { + if (!API::is_destroying(API::get_parent_window(arg.window_handle))) + place_ptr_->collocate(); + } } + else + erase_element(fastened, arg.window_handle); }); + + (to_fasten ? &fastened : &elements)->emplace_back(wd, evt); } field_interface& operator<<(const char* label_text) override @@ -666,33 +685,13 @@ namespace nana field_interface& operator<<(window wd) override { - if (API::empty_window(wd)) - throw std::invalid_argument("Place: An invalid window handle."); - - if (API::get_parent_window(wd) != place_ptr_->window_handle()) - throw std::invalid_argument("Place: the window is not a child of place bind window"); - - auto evt = _m_make_destroy(wd); - elements.emplace_back(wd, evt); + _m_insert_widget(wd, false); return *this; } field_interface& fasten(window wd) override { - if (API::empty_window(wd)) - throw std::invalid_argument("Place: An invalid window handle."); - - if (API::get_parent_window(wd) != place_ptr_->window_handle()) - throw std::invalid_argument("Place: the window is not a child of place bind window"); - - //Listen to destroy of a window. The deleting a fastened window - //does not change the layout. - auto evt = API::events(wd).destroy.connect([this](const arg_destroy& arg) - { - erase_element(fastened, arg.window_handle); - }); - - fastened.emplace_back(wd, evt); + _m_insert_widget(wd, true); return *this; } @@ -719,6 +718,12 @@ namespace nana };//end class field_dock + enum class fit_policy + { + none, //Doesn't fit the content + both, //Fits both width and height of content + single //Fits only width or height of content + }; class place::implement::division { @@ -773,7 +778,7 @@ namespace nana { auto child_floor = child->calc_weight_floor(); - if(child->weight.kind_of() == number_t::kind::percent) + if(child->is_percent()) { ratio += child->weight.real(); } @@ -785,24 +790,23 @@ namespace nana } auto const vert = (this->div_owner && (this->div_owner->kind_of_division == kind::vertical_arrange)); - double& fv = (vert ? floor.second : floor.first); - if(ratio > 0.001) - { - if(fv > 0) - fv = fv / ratio; - } + if((ratio > 0.001) && (fv > 0)) + fv /= ratio; if (!this->weight.empty()) { - if (this->weight.kind_of() != number_t::kind::percent) + if(!this->is_percent()) fv = this->weight.real(); } else { - if (this->fit_content) + if (fit_policy::none != this->fit) { + unsigned limited_px = 0; + bool limit_width = false; + std::size_t fit_count = 0; unsigned max_value = 0; for (auto & elm : this->field->elements) @@ -812,17 +816,11 @@ namespace nana { ++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; - } + + max_value = (std::max)(max_value, (vert ? extent->second.width : extent->second.height)); } } @@ -1006,7 +1004,7 @@ namespace nana kind kind_of_division; bool display{ true }; bool visible{ true }; - bool fit_content{ false }; + fit_policy fit{ fit_policy::none }; ::nana::direction dir{::nana::direction::west}; std::string name; std::vector> children; @@ -1109,27 +1107,21 @@ namespace nana bool moved = false; unsigned px = 0; - if (this->fit_content) + + auto move_r = element_r.result(); + if (fit_policy::both == this->fit) { auto extent = API::content_extent(el.handle, 0, false); if (extent) { - auto r = element_r.result(); - r.dimension(extent->second); + move_r.dimension(extent->second); if (vert) - { - if (area_margined.width > r.width) - r.x += (area_margined.width - r.width) / 2; - } + move_r.x += place_parts::differ(area_margined.width, move_r.width) / 2; else - { - if (area_margined.height > r.height) - r.y += (area_margined.height - r.height) / 2; - } + move_r.y += place_parts::differ(area_margined.height, move_r.height) / 2; - API::move_window(el.handle, r); - px = (vert ? r.height : r.width); + px = (vert ? move_r.height : move_r.width); moved = true; } } @@ -1138,9 +1130,11 @@ namespace nana { 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()); + move_r = element_r.result(); } + API::move_window(el.handle, move_r); + if (index + 1 < field->elements.size()) position += (px + calc_number(gap.at(index), area_px, 0, precise_px)); @@ -1260,7 +1254,7 @@ namespace nana return reached_mins; } - double _m_revise_adjustable(std::pair& fa, unsigned area_px) noexcept + double _m_revise_adjustable(std::pair& fa, unsigned area_px) { if (fa.first >= area_px || 0 == fa.second) return 0; @@ -1402,126 +1396,120 @@ namespace nana if (!field || !(visible && display)) return; - auto area = margin_area(); - - unsigned gap_size = 0; - auto gap_number = gap.at(0); - if (!gap_number.empty()) - gap_size = static_cast(gap_number.get_value(area.width)); - - //When the amount pixels of gaps is out of the area bound. - if ((gap_size * dimension.first >= area.width) || (gap_size * dimension.second >= area.height)) - { - for (auto & el : field->elements) - API::window_size(el.handle, size{ 0, 0 }); - return; - } + auto const area = margin_area(); + auto const gap_size = static_cast(gap.at(0).get_value(area.width)); //gap_size is 0 if gap isn't specified auto i = field->elements.cbegin(); auto const end = field->elements.cend(); - if (dimension.first <= 1 && dimension.second <= 1) + + //The total gaps must not beyond the bound of the area. + if ((gap_size * dimension.first < area.width) && (gap_size * dimension.second < area.height)) { - auto n_of_wd = field->elements.size(); - std::size_t edge; - switch (n_of_wd) + if (dimension.first <= 1 && dimension.second <= 1) { - case 0: - case 1: - edge = 1; break; - case 2: case 3: case 4: - edge = 2; break; - default: - edge = static_cast(std::sqrt(n_of_wd)); - if ((edge * edge) < n_of_wd) ++edge; - } - - 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)); - unsigned uns_block_w = static_cast(block_w); - unsigned uns_block_h = static_cast(block_h); - unsigned height = (uns_block_h > gap_size ? uns_block_h - gap_size : uns_block_h); - - std::size_t arr_pos = 0; - for (std::size_t u = 0; (u < edge && i != end); ++u) - { - double x = area.x; - for (std::size_t v = 0; (v < edge && i != end); ++v, ++i) + auto n_of_wd = field->elements.size(); + std::size_t edge; + switch (n_of_wd) { - unsigned value = 0; - auto arr = arrange_.at(arr_pos++); - - if (arr.empty()) - value = static_cast(block_w); - else - value = static_cast(arr.get_value(static_cast(area.width))); - - unsigned width = (value > uns_block_w ? uns_block_w : value); - if (width > gap_size) width -= gap_size; - API::move_window(i->handle, rectangle{ static_cast(x), static_cast(y), width, height }); - x += block_w; - } - y += block_h; - } - } - else - { - 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] }; - char *table = table_ptr.get(); - std::memset(table, 0, dimension.first * dimension.second); - - std::size_t lbp = 0; - - double precise_h = 0; - for (std::size_t u = 0; (u < dimension.second && i != end); ++u) - { - 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 v = 0; (v < dimension.first && i != end); ++v) - { - if (table[v + lbp]) - { - precise_w += block_w; - precise_w -= static_cast(precise_w); - continue; - } - - std::pair room{ 1, 1 }; - _m_find_collapse(static_cast(v), static_cast(u), room); - - 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[v + lbp] = 1; - } - else - { - precise_w += block_w * room.first + (room.first - 1) * gap_size; - result_h = static_cast(block_h * room.second + precise_h + (room.second - 1) * gap_size); - - for (unsigned y = 0; y < room.second; ++y) - for (unsigned x = 0; x < room.first; ++x) - table[v + x + lbp + y * dimension.first] = 1; - } - - unsigned result_w = static_cast(precise_w); - precise_w -= result_w; - - API::move_window(i->handle, rectangle{ pos_x, pos_y, result_w, result_h }); - ++i; + case 0: + case 1: + edge = 1; break; + case 2: case 3: case 4: + edge = 2; break; + default: + edge = static_cast(std::sqrt(n_of_wd)); + if ((edge * edge) < n_of_wd) ++edge; } - lbp += dimension.first; + double y = area.y; + const double block_w = area.width / double(edge); + const double block_h = area.height / double((n_of_wd / edge) + (n_of_wd % edge ? 1 : 0)); + const unsigned uns_block_w = static_cast(block_w); + const unsigned uns_block_h = static_cast(block_h); + const unsigned height = (uns_block_h > gap_size ? uns_block_h - gap_size : uns_block_h); + + std::size_t arr_pos = 0; + for (std::size_t u = 0; (u < edge && i != end); ++u) + { + double x = area.x; + for (std::size_t v = 0; (v < edge && i != end); ++v, ++i) + { + unsigned value = 0; + auto arr = arrange_.at(arr_pos++); + + if (arr.empty()) + value = static_cast(block_w); + else + value = static_cast(arr.get_value(static_cast(area.width))); + + unsigned width = (value > uns_block_w ? uns_block_w : value); + if (width > gap_size) width -= gap_size; + API::move_window(i->handle, rectangle{ static_cast(x), static_cast(y), width, height }); + x += block_w; + } + y += block_h; + } + } + else + { + const double block_w = int(area.width - gap_size * (dimension.first - 1)) / double(dimension.first); + const 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] }; + char *table = table_ptr.get(); + std::memset(table, 0, dimension.first * dimension.second); + + std::size_t lbp = 0; + + double precise_h = 0; + for (std::size_t u = 0; (u < dimension.second && i != end); ++u) + { + 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 v = 0; (v < dimension.first && i != end); ++v) + { + auto const epos = v + lbp; + if (table[epos]) + { + precise_w += block_w; + precise_w -= static_cast(precise_w); + continue; + } + + std::pair room{ 1, 1 }; + _m_find_collapse(static_cast(v), static_cast(u), room); + + const int pos_x = area.x + static_cast(v * (block_w + gap_size)); + const 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[epos] = 1; + } + else + { + precise_w += block_w * room.first + (room.first - 1) * gap_size; + result_h = static_cast(block_h * room.second + precise_h + (room.second - 1) * gap_size); + + for (unsigned y = 0; y < room.second; ++y) + for (unsigned x = 0; x < room.first; ++x) + table[epos + x + y * dimension.first] = 1; + } + + unsigned result_w = static_cast(precise_w); + precise_w -= result_w; + + API::move_window(i->handle, rectangle{ pos_x, pos_y, result_w, result_h }); + ++i; + } + + lbp += dimension.first; + } } } @@ -1598,6 +1586,9 @@ namespace nana if ((false == arg.left_button) && (mouse::left_button != arg.button)) return; + auto const leaf_left = _m_leaf(true); + auto const leaf_right = _m_leaf(false); + if (event_code::mouse_down == arg.evt_code) { begin_point_ = splitter_.pos(); @@ -1605,8 +1596,8 @@ namespace nana auto px_ptr = &nana::rectangle::width; //Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position - auto area_left = _m_leaf_left()->field_area; - auto area_right = _m_leaf_right()->field_area; + auto const area_left = leaf_left->field_area; + auto const area_right = leaf_right->field_area; if (nana::cursor::size_we != splitter_cursor_) { @@ -1635,29 +1626,29 @@ namespace nana if(!grabbed_) return; - const bool vert = (::nana::cursor::size_we != splitter_cursor_); - auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w(); - int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x); + auto const vert = (::nana::cursor::size_we != splitter_cursor_); + auto const delta = horz_point(vert, splitter_.pos() - begin_point_); const auto total_pixels = static_cast(left_pixels_ + right_pixels_); auto left_px = std::clamp(static_cast(left_pixels_) + delta, 0, total_pixels); + auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w(); 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); + left_px = static_cast(limit_px(leaf_left, left_px, area_px)); + leaf_left->weight.assign_percent(imd_rate * left_px); 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)); - _m_leaf_right()->weight.assign_percent(imd_rate * right_px); + right_px = static_cast(limit_px(leaf_right, right_px, area_px)); + leaf_right->weight.assign_percent(imd_rate * right_px); pause_move_collocate_ = true; div_owner->collocate(splitter_.parent()); //After the collocating, the splitter keeps the calculated weight of left division, //and clear the weight of right division. - _m_leaf_right()->weight.reset(); + leaf_right->weight.reset(); pause_move_collocate_ = false; } @@ -1675,8 +1666,8 @@ namespace nana { const bool vert = (::nana::cursor::size_we != splitter_cursor_); - auto leaf_left = _m_leaf_left(); - auto leaf_right = _m_leaf_right(); + auto leaf_left = _m_leaf(true); + auto leaf_right = _m_leaf(false); rectangle_rotator left(vert, leaf_left->field_area); rectangle_rotator right(vert, leaf_right->field_area); auto area_px = right.right() - left.x(); @@ -1806,16 +1797,19 @@ namespace nana void _m_update_div(std::string& div) { + auto const leaf_left = _m_leaf(true); + auto const leaf_right = _m_leaf(false); + std::string name; bool left = true; //Search a name recursively from a specified leaf field. //It returns the depth from the leaf div to the div which has a name. - auto depth = _m_search_name(_m_leaf_left(), name); + auto depth = _m_search_name(leaf_left, name); if (-1 == depth) { left = false; - depth = _m_search_name(_m_leaf_right(), name); + depth = _m_search_name(leaf_right, name); if (-1 == depth) return; } @@ -1839,8 +1833,8 @@ namespace nana const bool vert = (::nana::cursor::size_we != splitter_cursor_); - rectangle_rotator r_left(vert, _m_leaf_left()->field_area); - rectangle_rotator r_right(vert, _m_leaf_right()->field_area); + rectangle_rotator r_left(vert, leaf_left->field_area); + rectangle_rotator r_right(vert, leaf_right->field_area); rectangle_rotator r_owner(vert, this->div_owner->field_area); double percent = double((left ? r_left : r_right).w()) / double(r_owner.w()); @@ -1866,14 +1860,9 @@ namespace nana } } - division * _m_leaf_left() const + division * _m_leaf(bool left) const noexcept { - return previous(); - } - - division * _m_leaf_right() const - { - return div_next; + return (left ? previous() : div_next); } rectangle_rotator _m_update_splitter_range() @@ -1882,8 +1871,8 @@ namespace nana rectangle_rotator area(vert, div_owner->margin_area()); - auto leaf_left = _m_leaf_left(); - auto leaf_right = _m_leaf_right(); + auto leaf_left = _m_leaf(true); + auto leaf_right = _m_leaf(false); rectangle_rotator left(vert, leaf_left->field_area); rectangle_rotator right(vert, leaf_right->field_area); @@ -1982,7 +1971,7 @@ namespace nana void notify_move() override { - if (!_m_indicator()) + if (!_m_hit_test(false)) //hit test on indicator { indicator_.docker.reset(); return; @@ -2019,7 +2008,7 @@ namespace nana }); } - if (_m_dockable()) + if (_m_hit_test(true)) //hit test on docker { if (!indicator_.dock_area) { @@ -2078,7 +2067,8 @@ namespace nana void notify_move_stopped() override { - if (_m_dockable() && dockable_field && dockable_field->dockarea) + //hit test on docker + if (_m_hit_test(true) && dockable_field && dockable_field->dockarea) dockable_field->dockarea->dock(); indicator_.docker.reset(); @@ -2101,25 +2091,22 @@ namespace nana API::close_window(window_handle); } private: - bool _m_indicator() const + bool _m_hit_test(bool try_docker) const { - ::nana::point pos; - API::calc_screen_point(impl_ptr_->window_handle, pos); + window handle = nullptr; + if (try_docker) + { + if (!indicator_.docker) + return false; - rectangle r{ pos, API::window_size(impl_ptr_->window_handle) }; - return r.is_hit(API::cursor_position()); - } + handle = indicator_.docker->handle(); //hit test for docker + } + else + handle = impl_ptr_->window_handle; //hit test for indicator - bool _m_dockable() const - { - if (!indicator_.docker) - return false; - - ::nana::point pos; - API::calc_screen_point(indicator_.docker->handle(), pos); - - rectangle r{ pos, API::window_size(indicator_.docker->handle()) }; - return r.is_hit(API::cursor_position()); + point pos; + API::calc_screen_point(handle, pos); + return rectangle{ pos, API::window_size(handle) }.is_hit(API::cursor_position()); } public: field_dock * dockable_field{ nullptr }; @@ -2149,25 +2136,21 @@ namespace nana : panel(wd, true), dir_(dir), dock_dv_(dock_dv), pane_dv_(pane_dv) { this->bgcolor(colors::alice_blue); - this->cursor(_m_is_vert(dir_) ? ::nana::cursor::size_ns : ::nana::cursor::size_we); - + this->cursor(is_vert_dir(dir_) ? ::nana::cursor::size_ns : ::nana::cursor::size_we); auto grab_fn = [this, wd](const arg_mouse& arg) { + auto const is_vert = is_vert_dir(dir_); + if (event_code::mouse_down == arg.evt_code) //press mouse button { if (arg.button != ::nana::mouse::left_button) return; - bool is_vert = _m_is_vert(dir_); - this->set_capture(true); - auto basepos = API::cursor_position(); - base_pos_.x = (is_vert ? basepos.y : basepos.x); - - basepos = this->pos(); - base_pos_.y = (is_vert ? basepos.y : basepos.x); + base_pos_.x = horz_point(is_vert, API::cursor_position()); + base_pos_.y = horz_point(is_vert, this->pos()); base_px_ = (is_vert ? pane_dv_->field_area.height : pane_dv_->field_area.width); } @@ -2176,8 +2159,7 @@ namespace nana if (!arg.is_left_button()) return; - auto now_pos = API::cursor_position(); - int delta = (_m_is_vert(dir_) ? now_pos.y : now_pos.x) - base_pos_.x; + auto delta = horz_point(is_vert, API::cursor_position()) - base_pos_.x; int new_pos = base_pos_.y + delta; if (new_pos < range_.x) { @@ -2190,8 +2172,8 @@ namespace nana delta = new_pos - base_pos_.y; } - now_pos = this->pos(); - if (_m_is_vert(dir_)) + auto now_pos = this->pos(); + if (is_vert) now_pos.y = new_pos; else now_pos.x = new_pos; @@ -2218,7 +2200,7 @@ namespace nana break; } - auto dock_px = (_m_is_vert(dir_) ? dock_dv_->field_area.height : dock_dv_->field_area.width); + auto dock_px = (is_vert ? dock_dv_->field_area.height : dock_dv_->field_area.width); pane_dv_->weight.assign_percent(double(px) / double(dock_px) * 100); @@ -2278,7 +2260,7 @@ namespace nana if (!child->display) continue; - const auto is_vert = _m_is_vert(child->dir); + const auto is_vert = is_vert_dir(child->dir); if (is_first) { is_first = false; @@ -2318,7 +2300,7 @@ namespace nana } auto child_dv = dynamic_cast(child.get()); - const bool is_vert = _m_is_vert(child->dir); + const bool is_vert = is_vert_dir(child->dir); auto room_px = (is_vert ? room.height : room.width); @@ -2429,11 +2411,6 @@ namespace nana } } private: - static bool _m_is_vert(::nana::direction dir) - { - return (dir == ::nana::direction::north || dir == ::nana::direction::south); - } - static div_dockpane* _m_right(division* dv) { dv = dv->div_next; @@ -2521,7 +2498,6 @@ namespace nana 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(); @@ -2538,7 +2514,7 @@ namespace nana std::unique_ptr div; token div_type = token::eof; - bool fit_content = false; + auto fit = fit_policy::none; //These variables stand for the new division's attributes std::string name; @@ -2559,12 +2535,15 @@ namespace nana { case token::dock: if (token::eof != div_type && token::dock != div_type) - throw std::invalid_argument("nana.place: conflict of div type at " + tknizer.pos_str()); + throw std::invalid_argument("nana.place: conflict of div type at " + std::to_string(tknizer.pos())); div_type = token::dock; break; case token::fit: - fit_content = true; + fit = fit_policy::both; + break; + case token::fit_s: + fit = fit_policy::single; break; case token::splitter: //Ignore the splitter when there is not a division. @@ -2666,7 +2645,7 @@ namespace nana switch (tknizer.read()) { case token::number: - margin.set_value(tknizer.number()); + margin.push(tknizer.number(), true); break; case token::array: margin.set_array(tknizer.array()); @@ -2829,7 +2808,7 @@ namespace nana div->display = !undisplayed; div->visible = !(undisplayed || invisible); - div->fit_content = fit_content; + div->fit = fit; return div; } @@ -2891,20 +2870,20 @@ namespace nana if (i != docks.end()) { docks_to_be_closed.erase(div->name); - auto pane = dynamic_cast(div); - pane->dockable_field = i->second; - auto old_pane = pane->dockable_field->attached; - if (old_pane) + auto const pane = dynamic_cast(div); + auto fd_dock = pane->dockable_field; + fd_dock = i->second; + + if (fd_dock->attached) { - //old div_dockpane will be deleted - old_pane->dockable_field = nullptr; - div->display = old_pane->display; + fd_dock->attached->dockable_field = nullptr; + div->display = fd_dock->attached->display; } - pane->dockable_field->attached = pane; - if (pane->dockable_field->dockarea) - pane->dockable_field->dockarea->set_notifier(pane); + fd_dock->attached = pane; + if (fd_dock->dockarea) + fd_dock->dockarea->set_notifier(pane); } } else @@ -3035,7 +3014,6 @@ namespace nana throw std::invalid_argument(what); } - std::unique_ptr* replaced = nullptr; implement::division * div_owner = div_ptr->div_owner; diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 0be30e96..a3f5c8ae 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -29,21 +29,16 @@ namespace nana virtual ~splitter_interface(){} }; - class splitter_dtrigger - : public drawer_trigger - { - }; - template class splitter - : public widget_object ::type, splitter_dtrigger>, + : public widget_object ::type, drawer_trigger>, public splitter_interface { private: void _m_complete_creation() override { this->caption("place-splitter"); - widget_object ::type, splitter_dtrigger>::_m_complete_creation(); + widget_object ::type, drawer_trigger>::_m_complete_creation(); } }; @@ -92,7 +87,7 @@ namespace nana { color xclr = colors::red; - if(x_state_ == ::nana::mouse_action::pressed) + if(x_state_ == ::nana::mouse_action::pressed) xclr = xclr.blend(colors::white, 0.8); graph.rectangle(r, true, xclr); @@ -144,11 +139,8 @@ namespace nana private: ::nana::rectangle _m_button_area() const { - ::nana::rectangle r{API::window_size(window_handle_)}; - - r.x = r.right() - 20; - r.width = 20; - return r; + auto sz = API::window_size(window_handle_); + return{static_cast(sz.width) - 20, 0, 20, sz.height}; } public: window window_handle_; @@ -161,12 +153,17 @@ namespace nana }; class dockarea_caption - : public widget_object < category::widget_tag, dockcaption_dtrigger > + : public widget_object { public: using widget_object::get_drawer_trigger; }; + static unsigned differ(unsigned x, unsigned y) noexcept + { + return (x > y ? x - y : 0); + } + class dockarea : public widget_object { @@ -183,6 +180,7 @@ namespace nana { notifier_ = notifier; } + void create(window parent) { host_window_ = parent; @@ -191,17 +189,14 @@ namespace nana caption_.create(*this, true); caption_.get_drawer_trigger().on_close([this] { - bool destroy_dockarea = true; - if (tabbar_) { tabbar_->erase(tabbar_->selected()); - - destroy_dockarea = (0 == tabbar_->length()); + if (tabbar_->length()) + return; } - if (destroy_dockarea) - notifier_->request_close(); + notifier_->request_close(); }); this->events().resized.connect([this](const arg_resized& arg) @@ -331,14 +326,11 @@ namespace nana private: widget* _m_add_pane(factory & fn) { - rectangle r{ point(), this->size() }; + rectangle r{ this->size() }; //get a rectangle excluding caption r.y = 20; - if (r.height > 20) - r.height -= 20; - else - r.height = 0; + r.height = differ(r.height, 20); if (!tabbar_) { @@ -434,17 +426,8 @@ namespace nana bool is_negative() const { - switch (kind_) - { - case kind::integer: - return (value_.integer < 0); - case kind::real: - case kind::percent: - return (value_.real < 0); - default: - break; - } - return false; + return (((kind::integer == kind_) && (value_.integer < 0)) || + ((kind::real == kind_ || kind::percent == kind_) && (value_.real < 0))); } bool empty() const noexcept @@ -532,15 +515,12 @@ namespace nana all_edges_ = true; margins_.clear(); } - - void push(const number_t& v) + + void push(const number_t& v, bool reset = false) { - margins_.emplace_back(v); - } + if (reset) + clear(); - void set_value(const number_t& v) - { - clear(); margins_.emplace_back(v); } @@ -559,12 +539,11 @@ namespace nana if (all_edges_) { auto px = static_cast(margins_.back().get_value(static_cast(r.width))); - const auto dbl_px = static_cast(px << 1); r.x += px; - r.width = (r.width < dbl_px ? 0 : r.width - dbl_px); + r.width = differ(r.width, (static_cast(px) << 1)); r.y += px; - r.height = (r.height < dbl_px ? 0 : r.height - dbl_px); + r.height = differ(r.height, (static_cast(px) << 1)); } else { @@ -587,49 +566,44 @@ namespace nana ib = 2; } - typedef decltype(r.height) px_type; - auto calc = [](px_type a, px_type b) - { - return (a > b ? a - b : 0); - }; + using px_type = decltype(r.height); if (0 == it) //top { auto px = static_cast(margins_[it].get_value(static_cast(field_area.height))); r.y += px; - r.height = calc(r.height, static_cast(px)); + r.height = differ(r.height, static_cast(px)); } if (-1 != ib) //bottom { auto px = static_cast(margins_[ib].get_value(static_cast(field_area.height))); - r.height = calc(r.height, static_cast(px)); + r.height = differ(r.height, static_cast(px)); } if (-1 != il) //left { auto px = static_cast(margins_[il].get_value(static_cast(field_area.width))); r.x += px; - r.width = calc(r.width, static_cast(px)); + r.width = differ(r.width, static_cast(px)); } if (-1 != ir) //right { auto px = static_cast(margins_[ir].get_value(static_cast(field_area.width))); - r.width = calc(r.width, static_cast(px)); + r.width = differ(r.width, static_cast(px)); } } return r; } private: - bool all_edges_ = true; + bool all_edges_{ true }; std::vector margins_; };//end class margin class repeated_array { public: - //A workaround for VC2013, becuase it does not generated an implicit declared move-constructor as defaulted. repeated_array() = default; @@ -678,15 +652,10 @@ namespace nana number_t at(std::size_t pos) const { - if (values_.empty()) - return{}; + if (values_.size() && (repeated_ || pos < values_.size())) + return values_[pos % values_.size()]; - if (repeated_) - pos %= values_.size(); - else if (pos >= values_.size()) - return{}; - - return values_[pos]; + return{}; } private: bool repeated_ = false;