add support of div-text update for splitter(#157)
This commit is contained in:
parent
7f45ae4342
commit
5383d85cc0
@ -431,6 +431,87 @@ namespace nana
|
|||||||
}; //end class tokenizer
|
}; //end class tokenizer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool is_idchar(int ch)
|
||||||
|
{
|
||||||
|
return ('_' == ch || isalnum(ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0)
|
||||||
|
{
|
||||||
|
const auto len = std::strlen(idstr);
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = text.find(idstr, off)) != text.npos)
|
||||||
|
{
|
||||||
|
if (!is_idchar(text[pos + len]))
|
||||||
|
{
|
||||||
|
if (pos == 0 || !is_idchar(text[pos - 1]))
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
off = pos + len; // occurrence not found, advancing the offset and try again
|
||||||
|
}
|
||||||
|
return text.npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::size_t, std::size_t> get_field_bound(const std::string& div, const char* idstr, int depth)
|
||||||
|
{
|
||||||
|
auto start_pos = find_idstr(div, idstr);
|
||||||
|
|
||||||
|
if (depth < 0 || start_pos >= div.length())
|
||||||
|
return{};
|
||||||
|
|
||||||
|
const char* p = div.c_str() + start_pos;
|
||||||
|
|
||||||
|
while (depth >= 0)
|
||||||
|
{
|
||||||
|
auto pos = div.find_last_of("<>", start_pos);
|
||||||
|
if (div.npos == pos)
|
||||||
|
return{};
|
||||||
|
|
||||||
|
if (div[pos] == '>')
|
||||||
|
{
|
||||||
|
++depth;
|
||||||
|
start_pos = pos - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == depth)
|
||||||
|
{
|
||||||
|
start_pos = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
--depth;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//struct implement
|
//struct implement
|
||||||
struct place::implement
|
struct place::implement
|
||||||
{
|
{
|
||||||
@ -1315,8 +1396,9 @@ namespace nana
|
|||||||
|
|
||||||
enum{splitter_px = 4};
|
enum{splitter_px = 4};
|
||||||
public:
|
public:
|
||||||
div_splitter(place_parts::number_t init_weight)
|
div_splitter(place_parts::number_t init_weight, implement* impl):
|
||||||
: division(kind::splitter, std::string()),
|
division(kind::splitter, std::string()),
|
||||||
|
impl_(impl),
|
||||||
init_weight_(init_weight)
|
init_weight_(init_weight)
|
||||||
{
|
{
|
||||||
this->weight.assign(splitter_px);
|
this->weight.assign(splitter_px);
|
||||||
@ -1341,7 +1423,7 @@ namespace nana
|
|||||||
|
|
||||||
auto grab_fn = [this](const arg_mouse& arg)
|
auto grab_fn = [this](const arg_mouse& arg)
|
||||||
{
|
{
|
||||||
if (false == arg.left_button)
|
if ((false == arg.left_button) && (mouse::left_button != arg.button))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (event_code::mouse_down == arg.evt_code)
|
if (event_code::mouse_down == arg.evt_code)
|
||||||
@ -1374,6 +1456,7 @@ namespace nana
|
|||||||
else if(event_code::mouse_up == arg.evt_code)
|
else if(event_code::mouse_up == arg.evt_code)
|
||||||
{
|
{
|
||||||
grabbed_ = false;
|
grabbed_ = false;
|
||||||
|
this->_m_update_div(impl_->div_text);
|
||||||
}
|
}
|
||||||
else if (event_code::mouse_move == arg.evt_code)
|
else if (event_code::mouse_move == arg.evt_code)
|
||||||
{
|
{
|
||||||
@ -1472,6 +1555,231 @@ namespace nana
|
|||||||
splitter_.move(this->field_area);
|
splitter_.move(this->field_area);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
static int _m_search_name(const division* div, std::string& name)
|
||||||
|
{
|
||||||
|
if (div->name.size())
|
||||||
|
{
|
||||||
|
name = div->name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & child : div->children)
|
||||||
|
{
|
||||||
|
if (child->name.size())
|
||||||
|
{
|
||||||
|
name = child->name;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & child : div->children)
|
||||||
|
{
|
||||||
|
auto depth = _m_search_name(child.get(), name);
|
||||||
|
if (depth >= 0)
|
||||||
|
return depth + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<std::size_t, std::size_t> _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);
|
||||||
|
if (div.npos == attr_pos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::size_t off = 1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto pos = div.find('<', off);
|
||||||
|
if (div.npos == pos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (attr_pos < pos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int depth = 0;
|
||||||
|
off = pos + 1;
|
||||||
|
std::size_t endpos = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
endpos = div.find_first_of("<>", off);
|
||||||
|
if (div.npos == endpos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ('<' == div[endpos])
|
||||||
|
{
|
||||||
|
++depth;
|
||||||
|
off = endpos + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == depth)
|
||||||
|
break;
|
||||||
|
|
||||||
|
--depth;
|
||||||
|
off = endpos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr_pos < endpos)
|
||||||
|
{
|
||||||
|
attr_pos = div.find(attr, endpos + 1);
|
||||||
|
if (div.npos == attr_pos)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
off = endpos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto len = std::strlen(attr);
|
||||||
|
|
||||||
|
auto endpos = div.find_first_not_of(" ", attr_pos + len);
|
||||||
|
if (div.npos != endpos && div[endpos] == '=')
|
||||||
|
{
|
||||||
|
endpos = div.find_first_not_of(" 0123456789.%", endpos + 1);
|
||||||
|
if (div.npos == endpos)
|
||||||
|
throw std::runtime_error("please report an issue if throws");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
endpos = attr_pos + len;
|
||||||
|
|
||||||
|
div.erase(attr_pos, endpos - attr_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _m_update_div(std::string& div)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
if (-1 == depth)
|
||||||
|
{
|
||||||
|
left = false;
|
||||||
|
depth = _m_search_name(_m_leaf_right(), name);
|
||||||
|
if (-1 == depth)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the bound of field div-text through reverse recursion.
|
||||||
|
auto bound = get_field_bound(div, name.c_str(), depth);
|
||||||
|
if (bound.first == bound.second)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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_fieldstr = div.substr(other_bound.first, other_bound.second - other_bound.first);
|
||||||
|
_m_remove_attr(other_fieldstr, "weight");
|
||||||
|
|
||||||
|
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_owner(vert, this->div_owner->field_area);
|
||||||
|
|
||||||
|
double percent = double((left ? r_left : r_right).w()) / double(r_owner.w());
|
||||||
|
|
||||||
|
std::string weight = "weight=" + std::to_string(percent * 100) + "% ";
|
||||||
|
|
||||||
|
fieldstr.insert(1, weight);
|
||||||
|
|
||||||
|
//Replaces the 'right' field before 'left' in order to make the bound consistent
|
||||||
|
if (left)
|
||||||
|
{
|
||||||
|
if (other_fieldstr.length() != (other_bound.second - other_bound.first))
|
||||||
|
div.replace(other_bound.first, other_bound.second - other_bound.first, other_fieldstr);
|
||||||
|
|
||||||
|
div.replace(bound.first, bound.second - bound.first, fieldstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
div.replace(bound.first, bound.second - bound.first, fieldstr);
|
||||||
|
|
||||||
|
if (other_fieldstr.length() != (other_bound.second - other_bound.first))
|
||||||
|
div.replace(other_bound.first, other_bound.second - other_bound.first, other_fieldstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
division * _m_leaf_left() const
|
division * _m_leaf_left() const
|
||||||
{
|
{
|
||||||
return previous();
|
return previous();
|
||||||
@ -1532,6 +1840,7 @@ namespace nana
|
|||||||
return area;
|
return area;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
implement* const impl_;
|
||||||
nana::cursor splitter_cursor_{nana::cursor::arrow};
|
nana::cursor splitter_cursor_{nana::cursor::arrow};
|
||||||
place_parts::splitter<true> splitter_;
|
place_parts::splitter<true> splitter_;
|
||||||
nana::point begin_point_;
|
nana::point begin_point_;
|
||||||
@ -2171,7 +2480,7 @@ namespace nana
|
|||||||
//Ignore the splitter when there is not a division.
|
//Ignore the splitter when there is not a division.
|
||||||
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
|
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
|
||||||
{
|
{
|
||||||
auto splitter = new div_splitter(tknizer.number());
|
auto splitter = new div_splitter(tknizer.number(), this);
|
||||||
children.back()->div_next = splitter;
|
children.back()->div_next = splitter;
|
||||||
children.emplace_back(std::unique_ptr<division>{ splitter });
|
children.emplace_back(std::unique_ptr<division>{ splitter });
|
||||||
}
|
}
|
||||||
@ -2726,95 +3035,26 @@ namespace nana
|
|||||||
return *p;
|
return *p;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_idchar(int ch)
|
|
||||||
{
|
|
||||||
return ('_' == ch || isalnum(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0)
|
|
||||||
{
|
|
||||||
const auto len = std::strlen(idstr);
|
|
||||||
|
|
||||||
size_t pos;
|
|
||||||
while ((pos = text.find(idstr, off)) != text.npos)
|
|
||||||
{
|
|
||||||
if (!is_idchar(text[pos + len]))
|
|
||||||
{
|
|
||||||
if (pos == 0 || !is_idchar(text[pos - 1]))
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
off = pos + len; // occurrence not found, advancing the offset and try again
|
|
||||||
}
|
|
||||||
return text.npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_div(std::string& div, const char* field, const char* attr, update_operation operation)
|
void update_div(std::string& div, const char* field, const char* attr, update_operation operation)
|
||||||
{
|
{
|
||||||
const auto fieldname_pos = find_idstr(div, field);
|
const auto fieldname_pos = find_idstr(div, field);
|
||||||
if (div.npos == fieldname_pos)
|
if (div.npos == fieldname_pos)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Get the bounds of this field
|
auto bound = get_field_bound(div, field, 0);
|
||||||
std::size_t begin = 0, end = 0;
|
|
||||||
|
|
||||||
//Find the begin
|
|
||||||
int level = 0;
|
|
||||||
std::size_t pos = fieldname_pos;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
pos = div.find_last_of("<>", pos);
|
|
||||||
if (div.npos == pos)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ('<' == div[pos])
|
|
||||||
{
|
|
||||||
if (0 == level)
|
|
||||||
{
|
|
||||||
begin = pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
--level;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++level;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find the end
|
|
||||||
level = 0;
|
|
||||||
pos = fieldname_pos;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
pos = div.find_first_of("<>", pos);
|
|
||||||
if (div.npos == pos)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ('>' == div[pos])
|
|
||||||
{
|
|
||||||
if (0 == level)
|
|
||||||
{
|
|
||||||
end = pos + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
--level;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++level;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fieldstr = div.substr(begin + 1, end - begin - 2);
|
|
||||||
|
|
||||||
|
auto fieldstr = div.substr(bound.first + 1, bound.second - bound.first - 2);
|
||||||
//Search the attribute
|
//Search the attribute
|
||||||
for (pos = 0; true; ++pos)
|
std::size_t pos = 0;
|
||||||
|
int depth = 0;
|
||||||
|
for (; true; ++pos)
|
||||||
{
|
{
|
||||||
pos = find_idstr(fieldstr, attr, pos);
|
pos = find_idstr(fieldstr, attr, pos);
|
||||||
if (fieldstr.npos == pos)
|
if (fieldstr.npos == pos)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//Check if the attr is belong to this field.
|
//Check if the attr is belong to this field.
|
||||||
level = 0;
|
depth = 0;
|
||||||
std::size_t off = pos;
|
std::size_t off = pos;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -2823,16 +3063,16 @@ namespace nana
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if ('>' == fieldstr[off])
|
if ('>' == fieldstr[off])
|
||||||
++level;
|
++depth;
|
||||||
else
|
else
|
||||||
--level;
|
--depth;
|
||||||
|
|
||||||
if (0 == off)
|
if (0 == off)
|
||||||
break;
|
break;
|
||||||
--off;
|
--off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == level)
|
if (0 == depth)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2843,8 +3083,8 @@ namespace nana
|
|||||||
div.insert(fieldname_pos + std::strlen(field), " " + std::string(attr));
|
div.insert(fieldname_pos + std::strlen(field), " " + std::string(attr));
|
||||||
else if (operation == update_operation::replace)
|
else if (operation == update_operation::replace)
|
||||||
{
|
{
|
||||||
div.erase(begin + 1, fieldstr.length());
|
div.erase(bound.first + 1, fieldstr.length());
|
||||||
div.insert(begin + 1, std::string(attr) + " " + std::string(field));
|
div.insert(bound.first + 1, std::string(attr) + " " + std::string(field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2852,10 +3092,10 @@ namespace nana
|
|||||||
//There is an attribute
|
//There is an attribute
|
||||||
if (operation == update_operation::erase)
|
if (operation == update_operation::erase)
|
||||||
{
|
{
|
||||||
div.erase(begin + pos + 1, std::strlen(attr));
|
div.erase(bound.first + pos + 1, std::strlen(attr));
|
||||||
|
|
||||||
if ((div[begin + pos] == div[begin + pos + 1]) && (' ' == div[begin + pos]))
|
if ((div[bound.first + pos] == div[bound.first + pos + 1]) && (' ' == div[bound.first + pos]))
|
||||||
div.erase(begin + pos, 1);
|
div.erase(bound.first + pos, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user