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
|
||||
}
|
||||
|
||||
|
||||
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 place::implement
|
||||
{
|
||||
@ -1315,8 +1396,9 @@ namespace nana
|
||||
|
||||
enum{splitter_px = 4};
|
||||
public:
|
||||
div_splitter(place_parts::number_t init_weight)
|
||||
: division(kind::splitter, std::string()),
|
||||
div_splitter(place_parts::number_t init_weight, implement* impl):
|
||||
division(kind::splitter, std::string()),
|
||||
impl_(impl),
|
||||
init_weight_(init_weight)
|
||||
{
|
||||
this->weight.assign(splitter_px);
|
||||
@ -1341,7 +1423,7 @@ namespace nana
|
||||
|
||||
auto grab_fn = [this](const arg_mouse& arg)
|
||||
{
|
||||
if (false == arg.left_button)
|
||||
if ((false == arg.left_button) && (mouse::left_button != arg.button))
|
||||
return;
|
||||
|
||||
if (event_code::mouse_down == arg.evt_code)
|
||||
@ -1374,6 +1456,7 @@ namespace nana
|
||||
else if(event_code::mouse_up == arg.evt_code)
|
||||
{
|
||||
grabbed_ = false;
|
||||
this->_m_update_div(impl_->div_text);
|
||||
}
|
||||
else if (event_code::mouse_move == arg.evt_code)
|
||||
{
|
||||
@ -1472,6 +1555,231 @@ namespace nana
|
||||
splitter_.move(this->field_area);
|
||||
}
|
||||
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
|
||||
{
|
||||
return previous();
|
||||
@ -1532,6 +1840,7 @@ namespace nana
|
||||
return area;
|
||||
}
|
||||
private:
|
||||
implement* const impl_;
|
||||
nana::cursor splitter_cursor_{nana::cursor::arrow};
|
||||
place_parts::splitter<true> splitter_;
|
||||
nana::point begin_point_;
|
||||
@ -2171,7 +2480,7 @@ namespace nana
|
||||
//Ignore the splitter when there is not a 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.emplace_back(std::unique_ptr<division>{ splitter });
|
||||
}
|
||||
@ -2726,95 +3035,26 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
const auto fieldname_pos = find_idstr(div, field);
|
||||
if (div.npos == fieldname_pos)
|
||||
return;
|
||||
|
||||
//Get the bounds of this field
|
||||
std::size_t begin = 0, end = 0;
|
||||
|
||||
//Find the begin
|
||||
int level = 0;
|
||||
std::size_t pos = fieldname_pos;
|
||||
while (true)
|
||||
{
|
||||
pos = div.find_last_of("<>", pos);
|
||||
if (div.npos == pos)
|
||||
return;
|
||||
|
||||
if ('<' == div[pos])
|
||||
{
|
||||
if (0 == level)
|
||||
{
|
||||
begin = pos;
|
||||
break;
|
||||
}
|
||||
else
|
||||
--level;
|
||||
}
|
||||
else
|
||||
++level;
|
||||
}
|
||||
|
||||
//Find the end
|
||||
level = 0;
|
||||
pos = fieldname_pos;
|
||||
while (true)
|
||||
{
|
||||
pos = div.find_first_of("<>", pos);
|
||||
if (div.npos == pos)
|
||||
return;
|
||||
|
||||
if ('>' == div[pos])
|
||||
{
|
||||
if (0 == level)
|
||||
{
|
||||
end = pos + 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
--level;
|
||||
}
|
||||
else
|
||||
++level;
|
||||
}
|
||||
|
||||
auto fieldstr = div.substr(begin + 1, end - begin - 2);
|
||||
auto bound = get_field_bound(div, field, 0);
|
||||
|
||||
auto fieldstr = div.substr(bound.first + 1, bound.second - bound.first - 2);
|
||||
//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);
|
||||
if (fieldstr.npos == pos)
|
||||
break;
|
||||
|
||||
//Check if the attr is belong to this field.
|
||||
level = 0;
|
||||
depth = 0;
|
||||
std::size_t off = pos;
|
||||
while (true)
|
||||
{
|
||||
@ -2823,16 +3063,16 @@ namespace nana
|
||||
break;
|
||||
|
||||
if ('>' == fieldstr[off])
|
||||
++level;
|
||||
++depth;
|
||||
else
|
||||
--level;
|
||||
--depth;
|
||||
|
||||
if (0 == off)
|
||||
break;
|
||||
--off;
|
||||
}
|
||||
|
||||
if (0 == level)
|
||||
if (0 == depth)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2843,8 +3083,8 @@ namespace nana
|
||||
div.insert(fieldname_pos + std::strlen(field), " " + std::string(attr));
|
||||
else if (operation == update_operation::replace)
|
||||
{
|
||||
div.erase(begin + 1, fieldstr.length());
|
||||
div.insert(begin + 1, std::string(attr) + " " + std::string(field));
|
||||
div.erase(bound.first + 1, fieldstr.length());
|
||||
div.insert(bound.first + 1, std::string(attr) + " " + std::string(field));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2852,10 +3092,10 @@ namespace nana
|
||||
//There is an attribute
|
||||
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]))
|
||||
div.erase(begin + pos, 1);
|
||||
if ((div[bound.first + pos] == div[bound.first + pos + 1]) && (' ' == div[bound.first + pos]))
|
||||
div.erase(bound.first + pos, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user