add place::div() to return the div text

introduce keywords 'undisplayed' and 'invisible' into div-text
This commit is contained in:
Jinhao 2016-09-28 07:47:53 +08:00
parent 8b652ee308
commit 830839ae27
2 changed files with 159 additions and 3 deletions

View File

@ -113,6 +113,7 @@ namespace nana
window window_handle() const; window window_handle() const;
void div(const char* s); ///< Divides the attached widget into fields. void div(const char* s); ///< Divides the attached widget into fields.
const std::string& div() const noexcept; ///< Returns div-text that depends on fields status.
void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. void modify(const char* field_name, const char* div_text); ///< Modifies a specified field.
field_reference field(const char* name);///< Returns a field with the specified name. field_reference field(const char* name);///< Returns a field with the specified name.

View File

@ -56,7 +56,7 @@ namespace nana
{ {
div_start, div_end, splitter, div_start, div_end, splitter,
identifier, dock, vert, grid, number, array, reparray, identifier, dock, vert, grid, number, array, reparray,
weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible,
collapse, parameters, collapse, parameters,
equal, equal,
eof, error eof, error
@ -275,7 +275,7 @@ namespace nana
_m_throw_error("a parameter list is required after 'collapse'"); _m_throw_error("a parameter list is required after 'collapse'");
return token::collapse; return token::collapse;
} }
else if ("left" == idstr_ || "right" == idstr_ || "top" == idstr_ || "bottom" == idstr_) else if ("left" == idstr_ || "right" == idstr_ || "top" == idstr_ || "bottom" == idstr_ || "undisplayed" == idstr_ || "invisible" == idstr_)
{ {
switch (idstr_.front()) switch (idstr_.front())
{ {
@ -283,8 +283,11 @@ namespace nana
case 'r': return token::right; case 'r': return token::right;
case 't': return token::top; case 't': return token::top;
case 'b': return token::bottom; case 'b': return token::bottom;
case 'u': return token::undisplayed;
case 'i': return token::invisible;
} }
} }
return token::identifier; return token::identifier;
} }
@ -442,6 +445,8 @@ namespace nana
window window_handle{nullptr}; window window_handle{nullptr};
event_handle event_size_handle{nullptr}; event_handle event_size_handle{nullptr};
std::string div_text;
std::unique_ptr<division> root_division; std::unique_ptr<division> root_division;
std::map<std::string, field_gather*> fields; std::map<std::string, field_gather*> fields;
std::map<std::string, field_dock*> docks; std::map<std::string, field_dock*> docks;
@ -2147,6 +2152,9 @@ namespace nana
std::vector<std::unique_ptr<division>> children; std::vector<std::unique_ptr<division>> children;
::nana::direction div_dir = ::nana::direction::west; ::nana::direction div_dir = ::nana::direction::west;
bool undisplayed = false;
bool invisible = false;
for (token tk = tknizer.read(); tk != token::eof; tk = tknizer.read()) for (token tk = tknizer.read(); tk != token::eof; tk = tknizer.read())
{ {
bool exit_for = false; bool exit_for = false;
@ -2305,6 +2313,10 @@ namespace nana
div_dir = ::nana::direction::north; break; div_dir = ::nana::direction::north; break;
case token::bottom: case token::bottom:
div_dir = ::nana::direction::south; break; div_dir = ::nana::direction::south; break;
case token::undisplayed:
undisplayed = true; break;
case token::invisible:
invisible = true; break;
default: break; default: break;
} }
if (exit_for) if (exit_for)
@ -2430,6 +2442,9 @@ namespace nana
div->children.swap(children); div->children.swap(children);
div->margin = std::move(margin); div->margin = std::move(margin);
div->dir = div_dir; div->dir = div_dir;
div->display = !undisplayed;
div->visible = !(undisplayed || invisible);
return div; return div;
} }
@ -2593,6 +2608,7 @@ namespace nana
impl_->connect(div.get()); impl_->connect(div.get());
impl_->root_division.reset(); //clear atachments div-fields impl_->root_division.reset(); //clear atachments div-fields
impl_->root_division.swap(div); impl_->root_division.swap(div);
impl_->div_text.assign(s);
} }
catch (...) catch (...)
{ {
@ -2601,6 +2617,11 @@ namespace nana
} }
} }
const std::string& place::div() const noexcept
{
return impl_->div_text;
}
void place::modify(const char* name, const char* div_text) void place::modify(const char* name, const char* div_text)
{ {
if (nullptr == div_text) if (nullptr == div_text)
@ -2698,6 +2719,133 @@ namespace nana
return *p; return *p;
} }
bool is_idchar(int ch)
{
return ('_' == ch || isalpha(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);
auto pos = text.find(idstr, off);
if (text.npos == pos)
return text.npos;
if (pos && is_idchar(text[pos - 1]))
return text.npos;
if ((pos + len < text.length()) && is_idchar(text[pos + len]))
return text.npos;
return pos;
}
void update_div(std::string& div, const char* field, const char* attr, bool insertion)
{
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);
//Search the attribute
for (pos = 0; true; ++pos)
{
pos = find_idstr(fieldstr, attr, pos);
if (fieldstr.npos == pos)
break;
//Check if the attr is belong to this field.
level = 0;
std::size_t off = pos;
while (true)
{
off = fieldstr.find_last_of("<>", off);
if (fieldstr.npos == off)
break;
if ('>' == fieldstr[off])
++level;
else
--level;
if (0 == off)
break;
--off;
}
if (0 == level)
break;
}
if (fieldstr.npos == pos)
{
//There is not an attribute
if (insertion)
div.insert(fieldname_pos + std::strlen(field), " " + std::string(attr));
}
else
{
//There is an attribute
if (!insertion)
{
div.erase(begin + pos + 1, std::strlen(attr));
if ((div[begin + pos] == div[begin + pos + 1]) && (' ' == div[begin + pos]))
div.erase(begin + pos, 1);
}
}
}
void place::field_visible(const char* name, bool vsb) void place::field_visible(const char* name, bool vsb)
{ {
if (!name) name = ""; if (!name) name = "";
@ -2707,7 +2855,10 @@ namespace nana
auto div = impl_->search_div_name(impl_->root_division.get(), name); auto div = impl_->search_div_name(impl_->root_division.get(), name);
if (div) if (div)
{
div->set_visible(vsb); div->set_visible(vsb);
update_div(impl_->div_text, name, "invisible", !vsb);
}
} }
bool place::field_visible(const char* name) const bool place::field_visible(const char* name) const
@ -2730,8 +2881,12 @@ namespace nana
auto div = impl_->search_div_name(impl_->root_division.get(), name); auto div = impl_->search_div_name(impl_->root_division.get(), name);
if (div) if (div)
{
update_div(impl_->div_text, name, "invisible", false);
update_div(impl_->div_text, name, "undisplayed", !dsp);
div->set_display(dsp); div->set_display(dsp);
} }
}
bool place::field_display(const char* name) const bool place::field_display(const char* name) const
{ {