code refine

This commit is contained in:
Jinhao
2017-03-04 07:53:06 +08:00
parent 3e5c4133ce
commit f43d54d7e2
2 changed files with 276 additions and 329 deletions

View File

@@ -15,7 +15,6 @@
#include <cfloat> #include <cfloat>
#include <cmath> #include <cmath>
#include <map> #include <map>
#include <deque>
#include <algorithm> #include <algorithm>
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
#include <nana/deploy.hpp> #include <nana/deploy.hpp>
@@ -57,7 +56,7 @@ namespace nana
enum class token enum class token
{ {
div_start, div_end, splitter, 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, weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible,
collapse, parameters, collapse, parameters,
equal, equal,
@@ -73,7 +72,7 @@ namespace nana
return idstr_; return idstr_;
} }
number_t number() const const number_t& number() const
{ {
return number_; return number_;
} }
@@ -98,11 +97,6 @@ namespace nana
return (sp_ - divstr_); return (sp_ - divstr_);
} }
std::string pos_str() const
{
return std::to_string(pos());
}
token read() token read()
{ {
sp_ = _m_eat_whitespace(sp_); sp_ = _m_eat_whitespace(sp_);
@@ -255,6 +249,8 @@ namespace nana
return token::dock; return token::dock;
else if ("fit" == idstr_) else if ("fit" == idstr_)
return token::fit; return token::fit;
else if ("fit_s" == idstr_)
return token::fit_s;
else if ("vertical" == idstr_ || "vert" == idstr_) else if ("vertical" == idstr_ || "vert" == idstr_)
return token::vert; return token::vert;
else if ("variable" == idstr_ || "repeated" == idstr_) else if ("variable" == idstr_ || "repeated" == idstr_)
@@ -434,6 +430,16 @@ namespace nana
}; //end class tokenizer }; //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 static bool is_idchar(int ch) noexcept
{ {
@@ -640,18 +646,31 @@ namespace nana
return nullptr; return nullptr;
} }
private: private:
//Listen to destroy of a window void _m_insert_widget(window wd, bool to_fasten)
//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 (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))) if (erase_element(elements, arg.window_handle))
place_ptr_->collocate(); {
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 field_interface& operator<<(const char* label_text) override
@@ -666,33 +685,13 @@ namespace nana
field_interface& operator<<(window wd) override field_interface& operator<<(window wd) override
{ {
if (API::empty_window(wd)) _m_insert_widget(wd, false);
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);
return *this; return *this;
} }
field_interface& fasten(window wd) override field_interface& fasten(window wd) override
{ {
if (API::empty_window(wd)) _m_insert_widget(wd, true);
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);
return *this; return *this;
} }
@@ -719,6 +718,12 @@ namespace nana
};//end class field_dock };//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 class place::implement::division
{ {
@@ -773,7 +778,7 @@ namespace nana
{ {
auto child_floor = child->calc_weight_floor(); auto child_floor = child->calc_weight_floor();
if(child->weight.kind_of() == number_t::kind::percent) if(child->is_percent())
{ {
ratio += child->weight.real(); 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)); auto const vert = (this->div_owner && (this->div_owner->kind_of_division == kind::vertical_arrange));
double& fv = (vert ? floor.second : floor.first); double& fv = (vert ? floor.second : floor.first);
if(ratio > 0.001) if((ratio > 0.001) && (fv > 0))
{ fv /= ratio;
if(fv > 0)
fv = fv / ratio;
}
if (!this->weight.empty()) if (!this->weight.empty())
{ {
if (this->weight.kind_of() != number_t::kind::percent) if(!this->is_percent())
fv = this->weight.real(); fv = this->weight.real();
} }
else 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; std::size_t fit_count = 0;
unsigned max_value = 0; unsigned max_value = 0;
for (auto & elm : this->field->elements) for (auto & elm : this->field->elements)
@@ -812,17 +816,11 @@ namespace nana
{ {
++fit_count; ++fit_count;
if (vert) if (vert)
{
floor.second += extent->second.height; floor.second += extent->second.height;
if (extent->second.width > max_value)
max_value = extent->second.width;
}
else else
{
floor.first += extent->second.width; 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; kind kind_of_division;
bool display{ true }; bool display{ true };
bool visible{ true }; bool visible{ true };
bool fit_content{ false }; fit_policy fit{ fit_policy::none };
::nana::direction dir{::nana::direction::west}; ::nana::direction dir{::nana::direction::west};
std::string name; std::string name;
std::vector<std::unique_ptr<division>> children; std::vector<std::unique_ptr<division>> children;
@@ -1109,27 +1107,21 @@ namespace nana
bool moved = false; bool moved = false;
unsigned px = 0; 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); auto extent = API::content_extent(el.handle, 0, false);
if (extent) if (extent)
{ {
auto r = element_r.result(); move_r.dimension(extent->second);
r.dimension(extent->second);
if (vert) if (vert)
{ move_r.x += place_parts::differ(area_margined.width, move_r.width) / 2;
if (area_margined.width > r.width)
r.x += (area_margined.width - r.width) / 2;
}
else else
{ move_r.y += place_parts::differ(area_margined.height, move_r.height) / 2;
if (area_margined.height > r.height)
r.y += (area_margined.height - r.height) / 2;
}
API::move_window(el.handle, r); px = (vert ? move_r.height : move_r.width);
px = (vert ? r.height : r.width);
moved = true; moved = true;
} }
} }
@@ -1138,9 +1130,11 @@ namespace nana
{ {
px = calc_number(arrange_.at(index), area_px, adjustable_px, precise_px); px = calc_number(arrange_.at(index), area_px, adjustable_px, precise_px);
element_r.w_ref() = 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()) if (index + 1 < field->elements.size())
position += (px + calc_number(gap.at(index), area_px, 0, precise_px)); position += (px + calc_number(gap.at(index), area_px, 0, precise_px));
@@ -1260,7 +1254,7 @@ namespace nana
return reached_mins; return reached_mins;
} }
double _m_revise_adjustable(std::pair<unsigned, std::size_t>& fa, unsigned area_px) noexcept double _m_revise_adjustable(std::pair<unsigned, std::size_t>& fa, unsigned area_px)
{ {
if (fa.first >= area_px || 0 == fa.second) if (fa.first >= area_px || 0 == fa.second)
return 0; return 0;
@@ -1402,126 +1396,120 @@ namespace nana
if (!field || !(visible && display)) if (!field || !(visible && display))
return; return;
auto area = margin_area(); auto const area = margin_area();
auto const gap_size = static_cast<unsigned>(gap.at(0).get_value(area.width)); //gap_size is 0 if gap isn't specified
unsigned gap_size = 0;
auto gap_number = gap.at(0);
if (!gap_number.empty())
gap_size = static_cast<unsigned>(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 i = field->elements.cbegin(); auto i = field->elements.cbegin();
auto const end = field->elements.cend(); 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(); if (dimension.first <= 1 && dimension.second <= 1)
std::size_t edge;
switch (n_of_wd)
{ {
case 0: auto n_of_wd = field->elements.size();
case 1: std::size_t edge;
edge = 1; break; switch (n_of_wd)
case 2: case 3: case 4:
edge = 2; break;
default:
edge = static_cast<std::size_t>(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<unsigned>(block_w);
unsigned uns_block_h = static_cast<unsigned>(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)
{ {
unsigned value = 0; case 0:
auto arr = arrange_.at(arr_pos++); case 1:
edge = 1; break;
if (arr.empty()) case 2: case 3: case 4:
value = static_cast<decltype(value)>(block_w); edge = 2; break;
else default:
value = static_cast<decltype(value)>(arr.get_value(static_cast<int>(area.width))); edge = static_cast<std::size_t>(std::sqrt(n_of_wd));
if ((edge * edge) < n_of_wd) ++edge;
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<int>(x), static_cast<int>(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<char[]> 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<unsigned>(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<int>(precise_w);
continue;
}
std::pair<unsigned, unsigned> room{ 1, 1 };
_m_find_collapse(static_cast<int>(v), static_cast<int>(u), room);
int pos_x = area.x + static_cast<int>(v * (block_w + gap_size));
int pos_y = area.y + static_cast<int>(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<unsigned>(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<unsigned>(precise_w);
precise_w -= result_w;
API::move_window(i->handle, rectangle{ pos_x, pos_y, result_w, result_h });
++i;
} }
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<unsigned>(block_w);
const unsigned uns_block_h = static_cast<unsigned>(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<decltype(value)>(block_w);
else
value = static_cast<decltype(value)>(arr.get_value(static_cast<int>(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<int>(x), static_cast<int>(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<char[]> 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<unsigned>(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<int>(precise_w);
continue;
}
std::pair<unsigned, unsigned> room{ 1, 1 };
_m_find_collapse(static_cast<int>(v), static_cast<int>(u), room);
const int pos_x = area.x + static_cast<int>(v * (block_w + gap_size));
const int pos_y = area.y + static_cast<int>(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<unsigned>(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<unsigned>(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)) if ((false == arg.left_button) && (mouse::left_button != arg.button))
return; return;
auto const leaf_left = _m_leaf(true);
auto const leaf_right = _m_leaf(false);
if (event_code::mouse_down == arg.evt_code) if (event_code::mouse_down == arg.evt_code)
{ {
begin_point_ = splitter_.pos(); begin_point_ = splitter_.pos();
@@ -1605,8 +1596,8 @@ namespace nana
auto px_ptr = &nana::rectangle::width; auto px_ptr = &nana::rectangle::width;
//Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position //Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position
auto area_left = _m_leaf_left()->field_area; auto const area_left = leaf_left->field_area;
auto area_right = _m_leaf_right()->field_area; auto const area_right = leaf_right->field_area;
if (nana::cursor::size_we != splitter_cursor_) if (nana::cursor::size_we != splitter_cursor_)
{ {
@@ -1635,29 +1626,29 @@ namespace nana
if(!grabbed_) if(!grabbed_)
return; return;
const bool vert = (::nana::cursor::size_we != splitter_cursor_); auto const vert = (::nana::cursor::size_we != splitter_cursor_);
auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w(); auto const delta = horz_point(vert, splitter_.pos() - begin_point_);
int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x);
const auto total_pixels = static_cast<int>(left_pixels_ + right_pixels_); const auto total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
auto left_px = std::clamp(static_cast<int>(left_pixels_) + delta, 0, total_pixels); auto left_px = std::clamp(static_cast<int>(left_pixels_) + delta, 0, total_pixels);
auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w();
double imd_rate = 100.0 / area_px; double imd_rate = 100.0 / area_px;
left_px = static_cast<int>(limit_px(_m_leaf_left(), left_px, area_px)); left_px = static_cast<int>(limit_px(leaf_left, left_px, area_px));
_m_leaf_left()->weight.assign_percent(imd_rate * left_px); leaf_left->weight.assign_percent(imd_rate * left_px);
auto right_px = std::clamp(static_cast<int>(right_pixels_) - delta, 0, total_pixels); auto right_px = std::clamp(static_cast<int>(right_pixels_) - delta, 0, total_pixels);
right_px = static_cast<int>(limit_px(_m_leaf_right(), right_px, area_px)); right_px = static_cast<int>(limit_px(leaf_right, right_px, area_px));
_m_leaf_right()->weight.assign_percent(imd_rate * right_px); leaf_right->weight.assign_percent(imd_rate * right_px);
pause_move_collocate_ = true; pause_move_collocate_ = true;
div_owner->collocate(splitter_.parent()); div_owner->collocate(splitter_.parent());
//After the collocating, the splitter keeps the calculated weight of left division, //After the collocating, the splitter keeps the calculated weight of left division,
//and clear the weight of right division. //and clear the weight of right division.
_m_leaf_right()->weight.reset(); leaf_right->weight.reset();
pause_move_collocate_ = false; pause_move_collocate_ = false;
} }
@@ -1675,8 +1666,8 @@ namespace nana
{ {
const bool vert = (::nana::cursor::size_we != splitter_cursor_); const bool vert = (::nana::cursor::size_we != splitter_cursor_);
auto leaf_left = _m_leaf_left(); auto leaf_left = _m_leaf(true);
auto leaf_right = _m_leaf_right(); auto leaf_right = _m_leaf(false);
rectangle_rotator left(vert, leaf_left->field_area); rectangle_rotator left(vert, leaf_left->field_area);
rectangle_rotator right(vert, leaf_right->field_area); rectangle_rotator right(vert, leaf_right->field_area);
auto area_px = right.right() - left.x(); auto area_px = right.right() - left.x();
@@ -1806,16 +1797,19 @@ namespace nana
void _m_update_div(std::string& div) void _m_update_div(std::string& div)
{ {
auto const leaf_left = _m_leaf(true);
auto const leaf_right = _m_leaf(false);
std::string name; std::string name;
bool left = true; bool left = true;
//Search a name recursively from a specified leaf field. //Search a name recursively from a specified leaf field.
//It returns the depth from the leaf div to the div which has a name. //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) if (-1 == depth)
{ {
left = false; left = false;
depth = _m_search_name(_m_leaf_right(), name); depth = _m_search_name(leaf_right, name);
if (-1 == depth) if (-1 == depth)
return; return;
} }
@@ -1839,8 +1833,8 @@ namespace nana
const bool vert = (::nana::cursor::size_we != splitter_cursor_); const bool vert = (::nana::cursor::size_we != splitter_cursor_);
rectangle_rotator r_left(vert, _m_leaf_left()->field_area); rectangle_rotator r_left(vert, leaf_left->field_area);
rectangle_rotator r_right(vert, _m_leaf_right()->field_area); rectangle_rotator r_right(vert, leaf_right->field_area);
rectangle_rotator r_owner(vert, this->div_owner->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()); 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(); return (left ? previous() : div_next);
}
division * _m_leaf_right() const
{
return div_next;
} }
rectangle_rotator _m_update_splitter_range() rectangle_rotator _m_update_splitter_range()
@@ -1882,8 +1871,8 @@ namespace nana
rectangle_rotator area(vert, div_owner->margin_area()); rectangle_rotator area(vert, div_owner->margin_area());
auto leaf_left = _m_leaf_left(); auto leaf_left = _m_leaf(true);
auto leaf_right = _m_leaf_right(); auto leaf_right = _m_leaf(false);
rectangle_rotator left(vert, leaf_left->field_area); rectangle_rotator left(vert, leaf_left->field_area);
rectangle_rotator right(vert, leaf_right->field_area); rectangle_rotator right(vert, leaf_right->field_area);
@@ -1982,7 +1971,7 @@ namespace nana
void notify_move() override void notify_move() override
{ {
if (!_m_indicator()) if (!_m_hit_test(false)) //hit test on indicator
{ {
indicator_.docker.reset(); indicator_.docker.reset();
return; return;
@@ -2019,7 +2008,7 @@ namespace nana
}); });
} }
if (_m_dockable()) if (_m_hit_test(true)) //hit test on docker
{ {
if (!indicator_.dock_area) if (!indicator_.dock_area)
{ {
@@ -2078,7 +2067,8 @@ namespace nana
void notify_move_stopped() override 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(); dockable_field->dockarea->dock();
indicator_.docker.reset(); indicator_.docker.reset();
@@ -2101,25 +2091,22 @@ namespace nana
API::close_window(window_handle); API::close_window(window_handle);
} }
private: private:
bool _m_indicator() const bool _m_hit_test(bool try_docker) const
{ {
::nana::point pos; window handle = nullptr;
API::calc_screen_point(impl_ptr_->window_handle, pos); if (try_docker)
{
if (!indicator_.docker)
return false;
rectangle r{ pos, API::window_size(impl_ptr_->window_handle) }; handle = indicator_.docker->handle(); //hit test for docker
return r.is_hit(API::cursor_position()); }
} else
handle = impl_ptr_->window_handle; //hit test for indicator
bool _m_dockable() const point pos;
{ API::calc_screen_point(handle, pos);
if (!indicator_.docker) return rectangle{ pos, API::window_size(handle) }.is_hit(API::cursor_position());
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());
} }
public: public:
field_dock * dockable_field{ nullptr }; field_dock * dockable_field{ nullptr };
@@ -2149,25 +2136,21 @@ namespace nana
: panel<true>(wd, true), dir_(dir), dock_dv_(dock_dv), pane_dv_(pane_dv) : panel<true>(wd, true), dir_(dir), dock_dv_(dock_dv), pane_dv_(pane_dv)
{ {
this->bgcolor(colors::alice_blue); 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 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 (event_code::mouse_down == arg.evt_code) //press mouse button
{ {
if (arg.button != ::nana::mouse::left_button) if (arg.button != ::nana::mouse::left_button)
return; return;
bool is_vert = _m_is_vert(dir_);
this->set_capture(true); this->set_capture(true);
auto basepos = API::cursor_position(); base_pos_.x = horz_point(is_vert, API::cursor_position());
base_pos_.x = (is_vert ? basepos.y : basepos.x); base_pos_.y = horz_point(is_vert, this->pos());
basepos = this->pos();
base_pos_.y = (is_vert ? basepos.y : basepos.x);
base_px_ = (is_vert ? pane_dv_->field_area.height : pane_dv_->field_area.width); 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()) if (!arg.is_left_button())
return; return;
auto now_pos = API::cursor_position(); auto delta = horz_point(is_vert, API::cursor_position()) - base_pos_.x;
int delta = (_m_is_vert(dir_) ? now_pos.y : now_pos.x) - base_pos_.x;
int new_pos = base_pos_.y + delta; int new_pos = base_pos_.y + delta;
if (new_pos < range_.x) if (new_pos < range_.x)
{ {
@@ -2190,8 +2172,8 @@ namespace nana
delta = new_pos - base_pos_.y; delta = new_pos - base_pos_.y;
} }
now_pos = this->pos(); auto now_pos = this->pos();
if (_m_is_vert(dir_)) if (is_vert)
now_pos.y = new_pos; now_pos.y = new_pos;
else else
now_pos.x = new_pos; now_pos.x = new_pos;
@@ -2218,7 +2200,7 @@ namespace nana
break; 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); pane_dv_->weight.assign_percent(double(px) / double(dock_px) * 100);
@@ -2278,7 +2260,7 @@ namespace nana
if (!child->display) if (!child->display)
continue; continue;
const auto is_vert = _m_is_vert(child->dir); const auto is_vert = is_vert_dir(child->dir);
if (is_first) if (is_first)
{ {
is_first = false; is_first = false;
@@ -2318,7 +2300,7 @@ namespace nana
} }
auto child_dv = dynamic_cast<div_dockpane*>(child.get()); auto child_dv = dynamic_cast<div_dockpane*>(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); auto room_px = (is_vert ? room.height : room.width);
@@ -2429,11 +2411,6 @@ namespace nana
} }
} }
private: 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) static div_dockpane* _m_right(division* dv)
{ {
dv = dv->div_next; dv = dv->div_next;
@@ -2521,7 +2498,6 @@ namespace nana
static int get_parameter(place_parts::tokenizer& tknizer, std::size_t pos) static int get_parameter(place_parts::tokenizer& tknizer, std::size_t pos)
{ {
auto & arg = tknizer.parameters()[pos]; auto & arg = tknizer.parameters()[pos];
//auto & arg = params[pos];
if (arg.kind_of() == number_t::kind::integer) if (arg.kind_of() == number_t::kind::integer)
return arg.integer(); return arg.integer();
@@ -2538,7 +2514,7 @@ namespace nana
std::unique_ptr<division> div; std::unique_ptr<division> div;
token div_type = token::eof; token div_type = token::eof;
bool fit_content = false; auto fit = fit_policy::none;
//These variables stand for the new division's attributes //These variables stand for the new division's attributes
std::string name; std::string name;
@@ -2559,12 +2535,15 @@ namespace nana
{ {
case token::dock: case token::dock:
if (token::eof != div_type && token::dock != div_type) 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; div_type = token::dock;
break; break;
case token::fit: case token::fit:
fit_content = true; fit = fit_policy::both;
break;
case token::fit_s:
fit = fit_policy::single;
break; break;
case token::splitter: case token::splitter:
//Ignore the splitter when there is not a division. //Ignore the splitter when there is not a division.
@@ -2666,7 +2645,7 @@ namespace nana
switch (tknizer.read()) switch (tknizer.read())
{ {
case token::number: case token::number:
margin.set_value(tknizer.number()); margin.push(tknizer.number(), true);
break; break;
case token::array: case token::array:
margin.set_array(tknizer.array()); margin.set_array(tknizer.array());
@@ -2829,7 +2808,7 @@ namespace nana
div->display = !undisplayed; div->display = !undisplayed;
div->visible = !(undisplayed || invisible); div->visible = !(undisplayed || invisible);
div->fit_content = fit_content; div->fit = fit;
return div; return div;
} }
@@ -2891,20 +2870,20 @@ namespace nana
if (i != docks.end()) if (i != docks.end())
{ {
docks_to_be_closed.erase(div->name); docks_to_be_closed.erase(div->name);
auto pane = dynamic_cast<div_dockpane*>(div);
pane->dockable_field = i->second;
auto old_pane = pane->dockable_field->attached; auto const pane = dynamic_cast<div_dockpane*>(div);
if (old_pane) auto fd_dock = pane->dockable_field;
fd_dock = i->second;
if (fd_dock->attached)
{ {
//old div_dockpane will be deleted fd_dock->attached->dockable_field = nullptr;
old_pane->dockable_field = nullptr; div->display = fd_dock->attached->display;
div->display = old_pane->display;
} }
pane->dockable_field->attached = pane;
if (pane->dockable_field->dockarea) fd_dock->attached = pane;
pane->dockable_field->dockarea->set_notifier(pane); if (fd_dock->dockarea)
fd_dock->dockarea->set_notifier(pane);
} }
} }
else else
@@ -3035,7 +3014,6 @@ namespace nana
throw std::invalid_argument(what); throw std::invalid_argument(what);
} }
std::unique_ptr<implement::division>* replaced = nullptr; std::unique_ptr<implement::division>* replaced = nullptr;
implement::division * div_owner = div_ptr->div_owner; implement::division * div_owner = div_ptr->div_owner;

View File

@@ -29,21 +29,16 @@ namespace nana
virtual ~splitter_interface(){} virtual ~splitter_interface(){}
}; };
class splitter_dtrigger
: public drawer_trigger
{
};
template<bool IsLite> template<bool IsLite>
class splitter class splitter
: public widget_object <typename std::conditional<IsLite, category::lite_widget_tag, category::widget_tag>::type, splitter_dtrigger>, : public widget_object <typename std::conditional<IsLite, category::lite_widget_tag, category::widget_tag>::type, drawer_trigger>,
public splitter_interface public splitter_interface
{ {
private: private:
void _m_complete_creation() override void _m_complete_creation() override
{ {
this->caption("place-splitter"); this->caption("place-splitter");
widget_object <typename std::conditional<IsLite, category::lite_widget_tag, category::widget_tag>::type, splitter_dtrigger>::_m_complete_creation(); widget_object <typename std::conditional<IsLite, category::lite_widget_tag, category::widget_tag>::type, drawer_trigger>::_m_complete_creation();
} }
}; };
@@ -92,7 +87,7 @@ namespace nana
{ {
color xclr = colors::red; 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); xclr = xclr.blend(colors::white, 0.8);
graph.rectangle(r, true, xclr); graph.rectangle(r, true, xclr);
@@ -144,11 +139,8 @@ namespace nana
private: private:
::nana::rectangle _m_button_area() const ::nana::rectangle _m_button_area() const
{ {
::nana::rectangle r{API::window_size(window_handle_)}; auto sz = API::window_size(window_handle_);
return{static_cast<int>(sz.width) - 20, 0, 20, sz.height};
r.x = r.right() - 20;
r.width = 20;
return r;
} }
public: public:
window window_handle_; window window_handle_;
@@ -161,12 +153,17 @@ namespace nana
}; };
class dockarea_caption class dockarea_caption
: public widget_object < category::widget_tag, dockcaption_dtrigger > : public widget_object<category::widget_tag, dockcaption_dtrigger>
{ {
public: public:
using widget_object<category::widget_tag, dockcaption_dtrigger>::get_drawer_trigger; using widget_object<category::widget_tag, dockcaption_dtrigger>::get_drawer_trigger;
}; };
static unsigned differ(unsigned x, unsigned y) noexcept
{
return (x > y ? x - y : 0);
}
class dockarea class dockarea
: public widget_object <category::lite_widget_tag, drawer_trigger> : public widget_object <category::lite_widget_tag, drawer_trigger>
{ {
@@ -183,6 +180,7 @@ namespace nana
{ {
notifier_ = notifier; notifier_ = notifier;
} }
void create(window parent) void create(window parent)
{ {
host_window_ = parent; host_window_ = parent;
@@ -191,17 +189,14 @@ namespace nana
caption_.create(*this, true); caption_.create(*this, true);
caption_.get_drawer_trigger().on_close([this] caption_.get_drawer_trigger().on_close([this]
{ {
bool destroy_dockarea = true;
if (tabbar_) if (tabbar_)
{ {
tabbar_->erase(tabbar_->selected()); tabbar_->erase(tabbar_->selected());
if (tabbar_->length())
destroy_dockarea = (0 == tabbar_->length()); return;
} }
if (destroy_dockarea) notifier_->request_close();
notifier_->request_close();
}); });
this->events().resized.connect([this](const arg_resized& arg) this->events().resized.connect([this](const arg_resized& arg)
@@ -331,14 +326,11 @@ namespace nana
private: private:
widget* _m_add_pane(factory & fn) widget* _m_add_pane(factory & fn)
{ {
rectangle r{ point(), this->size() }; rectangle r{ this->size() };
//get a rectangle excluding caption //get a rectangle excluding caption
r.y = 20; r.y = 20;
if (r.height > 20) r.height = differ(r.height, 20);
r.height -= 20;
else
r.height = 0;
if (!tabbar_) if (!tabbar_)
{ {
@@ -434,17 +426,8 @@ namespace nana
bool is_negative() const bool is_negative() const
{ {
switch (kind_) return (((kind::integer == kind_) && (value_.integer < 0)) ||
{ ((kind::real == kind_ || kind::percent == kind_) && (value_.real < 0)));
case kind::integer:
return (value_.integer < 0);
case kind::real:
case kind::percent:
return (value_.real < 0);
default:
break;
}
return false;
} }
bool empty() const noexcept bool empty() const noexcept
@@ -533,14 +516,11 @@ namespace nana
margins_.clear(); 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); margins_.emplace_back(v);
} }
@@ -559,12 +539,11 @@ namespace nana
if (all_edges_) if (all_edges_)
{ {
auto px = static_cast<int>(margins_.back().get_value(static_cast<int>(r.width))); auto px = static_cast<int>(margins_.back().get_value(static_cast<int>(r.width)));
const auto dbl_px = static_cast<unsigned>(px << 1);
r.x += px; r.x += px;
r.width = (r.width < dbl_px ? 0 : r.width - dbl_px); r.width = differ(r.width, (static_cast<unsigned>(px) << 1));
r.y += px; r.y += px;
r.height = (r.height < dbl_px ? 0 : r.height - dbl_px); r.height = differ(r.height, (static_cast<unsigned>(px) << 1));
} }
else else
{ {
@@ -587,49 +566,44 @@ namespace nana
ib = 2; ib = 2;
} }
typedef decltype(r.height) px_type; using px_type = decltype(r.height);
auto calc = [](px_type a, px_type b)
{
return (a > b ? a - b : 0);
};
if (0 == it) //top if (0 == it) //top
{ {
auto px = static_cast<int>(margins_[it].get_value(static_cast<int>(field_area.height))); auto px = static_cast<int>(margins_[it].get_value(static_cast<int>(field_area.height)));
r.y += px; r.y += px;
r.height = calc(r.height, static_cast<px_type>(px)); r.height = differ(r.height, static_cast<px_type>(px));
} }
if (-1 != ib) //bottom if (-1 != ib) //bottom
{ {
auto px = static_cast<int>(margins_[ib].get_value(static_cast<int>(field_area.height))); auto px = static_cast<int>(margins_[ib].get_value(static_cast<int>(field_area.height)));
r.height = calc(r.height, static_cast<px_type>(px)); r.height = differ(r.height, static_cast<px_type>(px));
} }
if (-1 != il) //left if (-1 != il) //left
{ {
auto px = static_cast<px_type>(margins_[il].get_value(static_cast<int>(field_area.width))); auto px = static_cast<px_type>(margins_[il].get_value(static_cast<int>(field_area.width)));
r.x += px; r.x += px;
r.width = calc(r.width, static_cast<px_type>(px)); r.width = differ(r.width, static_cast<px_type>(px));
} }
if (-1 != ir) //right if (-1 != ir) //right
{ {
auto px = static_cast<int>(margins_[ir].get_value(static_cast<int>(field_area.width))); auto px = static_cast<int>(margins_[ir].get_value(static_cast<int>(field_area.width)));
r.width = calc(r.width, static_cast<px_type>(px)); r.width = differ(r.width, static_cast<px_type>(px));
} }
} }
return r; return r;
} }
private: private:
bool all_edges_ = true; bool all_edges_{ true };
std::vector<number_t> margins_; std::vector<number_t> margins_;
};//end class margin };//end class margin
class repeated_array class repeated_array
{ {
public: public:
//A workaround for VC2013, becuase it does not generated an implicit declared move-constructor as defaulted. //A workaround for VC2013, becuase it does not generated an implicit declared move-constructor as defaulted.
repeated_array() = default; repeated_array() = default;
@@ -678,15 +652,10 @@ namespace nana
number_t at(std::size_t pos) const number_t at(std::size_t pos) const
{ {
if (values_.empty()) if (values_.size() && (repeated_ || pos < values_.size()))
return{}; return values_[pos % values_.size()];
if (repeated_) return{};
pos %= values_.size();
else if (pos >= values_.size())
return{};
return values_[pos];
} }
private: private:
bool repeated_ = false; bool repeated_ = false;