refactor text_renderer
This commit is contained in:
@@ -16,7 +16,7 @@ namespace nana
|
|||||||
auto const end = str + len;
|
auto const end = str + len;
|
||||||
for(auto i = str; i != end; ++i)
|
for(auto i = str; i != end; ++i)
|
||||||
{
|
{
|
||||||
if(*i == '\n')
|
if('\n' == *i)
|
||||||
{
|
{
|
||||||
top += static_cast<int>(f(top, str, i - str));
|
top += static_cast<int>(f(top, str, i - str));
|
||||||
str = i + 1;
|
str = i + 1;
|
||||||
@@ -26,166 +26,125 @@ namespace nana
|
|||||||
f(top, str, end - str);
|
f(top, str, end - str);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct draw_string
|
|
||||||
{
|
|
||||||
drawable_type dw;
|
|
||||||
const int x, endpos;
|
|
||||||
align text_align;
|
|
||||||
|
|
||||||
draw_string(drawable_type dw, int x, int endpos, align ta)
|
class string_drawer
|
||||||
: dw(dw), x(x), endpos(endpos), text_align(ta)
|
{
|
||||||
{}
|
public:
|
||||||
|
string_drawer(graphics& graph, int left, int right, align ta, bool use_ellipsis):
|
||||||
|
graph_(graph),
|
||||||
|
left_(left),
|
||||||
|
right_(right),
|
||||||
|
text_align_(ta)
|
||||||
|
{
|
||||||
|
if (use_ellipsis)
|
||||||
|
{
|
||||||
|
#ifdef _nana_std_has_string_view
|
||||||
|
ellipsis_px_ = graph.text_extent_size(std::string_view{ "...", 3 }).width;
|
||||||
|
#else
|
||||||
|
ellipsis_px_ = graph.text_extent_size("...", 3).width;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
|
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
|
||||||
{
|
{
|
||||||
|
auto const drawable = graph_.handle();
|
||||||
auto const reordered = unicode_reorder(buf, bufsize);
|
auto const reordered = unicode_reorder(buf, bufsize);
|
||||||
if (reordered.empty())
|
|
||||||
return 0;
|
unsigned return_max_height = 0;
|
||||||
|
unsigned string_px = 0;
|
||||||
|
std::vector<nana::size> word_metrics;
|
||||||
|
for (auto & ent : reordered)
|
||||||
|
{
|
||||||
|
auto word_sz = detail::text_extent_size(drawable, ent.begin, ent.end - ent.begin);
|
||||||
|
word_metrics.push_back(word_sz);
|
||||||
|
|
||||||
nana::point pos{ x, top };
|
string_px += word_sz.width;
|
||||||
unsigned pixels = 0;
|
if (word_sz.height > return_max_height)
|
||||||
|
return_max_height = word_sz.height;
|
||||||
|
}
|
||||||
|
|
||||||
switch(text_align)
|
auto text_align = text_align_;
|
||||||
|
// Checks if ellipsis is enabled and the total pixels of string is larger than the space.
|
||||||
|
if (ellipsis_px_ && (string_px > static_cast<int>(right_ - left_)))
|
||||||
|
{
|
||||||
|
//The string should be drawn from left most point no matter what text align is.
|
||||||
|
text_align = align::left;
|
||||||
|
}
|
||||||
|
|
||||||
|
nana::point pos{ left_, top };
|
||||||
|
|
||||||
|
auto wdm = word_metrics.data();
|
||||||
|
switch (text_align)
|
||||||
{
|
{
|
||||||
case align::left:
|
case align::left:
|
||||||
for(auto & ent : reordered)
|
for (auto & ent : reordered)
|
||||||
{
|
{
|
||||||
std::size_t len = ent.end - ent.begin;
|
if (pos.x + static_cast<int>(wdm->width) > 0)
|
||||||
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
|
{
|
||||||
|
if (pos.x + static_cast<int>(wdm->width) <= right_ - static_cast<int>(ellipsis_px_))
|
||||||
|
{
|
||||||
|
//This word can be fully painted.
|
||||||
|
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//This word is painted partially. Firstly, paints the word on a dummy graphics buffer.
|
||||||
|
|
||||||
if(ts.height > pixels) pixels = ts.height;
|
nana::rectangle r{ nana::size{ static_cast<unsigned>(right_ - ellipsis_px_) - pos.x, wdm->height } };
|
||||||
|
|
||||||
if(pos.x + static_cast<int>(ts.width) > 0)
|
|
||||||
detail::draw_string(dw, pos, ent.begin, len);
|
|
||||||
|
|
||||||
pos.x += static_cast<int>(ts.width);
|
nana::paint::graphics dummy({ r.width, r.height });
|
||||||
if(pos.x >= endpos)
|
dummy.typeface(graph_.typeface());
|
||||||
|
|
||||||
|
dummy.bitblt(r, graph_, pos);
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_string_view
|
||||||
|
dummy.string({}, { ent.begin, ent.end - ent.begin }, graph_.palette(true));
|
||||||
|
#else
|
||||||
|
dummy.palette(true, graph_.palette(true));
|
||||||
|
dummy.string({}, ent.begin, ent.end - ent.begin);
|
||||||
|
#endif
|
||||||
|
r.x = pos.x;
|
||||||
|
r.y = top;
|
||||||
|
graph_.bitblt(r, dummy);
|
||||||
|
if (ellipsis_px_)
|
||||||
|
detail::draw_string(drawable, point{ right_ - static_cast<int>(ellipsis_px_), top }, L"...", 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.x += static_cast<int>(wdm->width);
|
||||||
|
if (pos.x > right_ - static_cast<int>(ellipsis_px_))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
++wdm;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case align::center:
|
case align::center:
|
||||||
|
pos.x = (right_ - left_ - string_px) / 2;
|
||||||
|
for (auto & ent : reordered)
|
||||||
{
|
{
|
||||||
unsigned lenpx = 0;
|
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
|
||||||
std::unique_ptr<unsigned[]> entity_pxs(new unsigned[reordered.size()]);
|
pos.x += (wdm++)->width;
|
||||||
|
|
||||||
auto ent_px = entity_pxs.get();
|
|
||||||
|
|
||||||
for(auto & ent : reordered)
|
|
||||||
{
|
|
||||||
auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin);
|
|
||||||
if(ts.height > pixels) pixels = ts.height;
|
|
||||||
lenpx += ts.width;
|
|
||||||
*ent_px++ = ts.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos.x += (endpos - pos.x - static_cast<int>(lenpx))/2;
|
|
||||||
ent_px = entity_pxs.get();
|
|
||||||
|
|
||||||
for(auto & ent : reordered)
|
|
||||||
{
|
|
||||||
if (pos.x + static_cast<int>(*ent_px) > 0)
|
|
||||||
detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin);
|
|
||||||
|
|
||||||
pos.x += static_cast<int>(*ent_px++);
|
|
||||||
|
|
||||||
if(pos.x >= endpos)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case align::right:
|
case align::right:
|
||||||
|
wdm = word_metrics.data() + word_metrics.size() - 1;
|
||||||
|
pos.x = right_;
|
||||||
|
for (auto i = reordered.crbegin(); i != reordered.crend(); ++i)
|
||||||
{
|
{
|
||||||
int xend = endpos;
|
pos.x -= (wdm--)->width;
|
||||||
std::swap(pos.x, xend);
|
detail::draw_string(drawable, pos, i->begin, i->end - i->begin);
|
||||||
for(auto i = reordered.crbegin(); i != reordered.crend(); ++i)
|
|
||||||
{
|
|
||||||
auto & ent = *i;
|
|
||||||
std::size_t len = ent.end - ent.begin;
|
|
||||||
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
|
|
||||||
if(ts.height > pixels) pixels = ts.height;
|
|
||||||
|
|
||||||
if(pos.x > xend)
|
|
||||||
{
|
|
||||||
pos.x -= static_cast<int>(ts.width);
|
|
||||||
detail::draw_string(dw, pos, i->begin, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pos.x <= xend || pos.x <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return pixels;
|
return return_max_height;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct draw_string_omitted
|
|
||||||
{
|
|
||||||
graphics & graph;
|
|
||||||
int x, endpos;
|
|
||||||
unsigned omitted_pixels;
|
|
||||||
|
|
||||||
draw_string_omitted(graphics& graph, int x, int endpos, bool omitted)
|
|
||||||
: graph(graph), x(x), endpos(endpos)
|
|
||||||
{
|
|
||||||
#ifdef _nana_std_has_string_view
|
|
||||||
omitted_pixels = (omitted ? graph.text_extent_size(std::string_view{ "...", 3 }).width : 0);
|
|
||||||
#else
|
|
||||||
omitted_pixels = (omitted ? graph.text_extent_size("...", 3).width : 0);
|
|
||||||
#endif
|
|
||||||
if (endpos - x > static_cast<int>(omitted_pixels))
|
|
||||||
this->endpos -= omitted_pixels;
|
|
||||||
else
|
|
||||||
this->endpos = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize)
|
|
||||||
{
|
|
||||||
drawable_type dw = graph.handle();
|
|
||||||
::nana::point pos{ x, top };
|
|
||||||
unsigned pixels = 0;
|
|
||||||
|
|
||||||
auto const reordered = unicode_reorder(buf, bufsize);
|
|
||||||
|
|
||||||
for(auto & i : reordered)
|
|
||||||
{
|
|
||||||
std::size_t len = i.end - i.begin;
|
|
||||||
nana::size ts = detail::text_extent_size(dw, i.begin, len);
|
|
||||||
if(ts.height > pixels) pixels = ts.height;
|
|
||||||
|
|
||||||
if(pos.x + static_cast<int>(ts.width) <= endpos)
|
|
||||||
{
|
|
||||||
detail::draw_string(dw, pos, i.begin, len);
|
|
||||||
pos.x += static_cast<int>(ts.width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nana::rectangle r;
|
|
||||||
r.width = endpos - pos.x;
|
|
||||||
r.height = ts.height;
|
|
||||||
|
|
||||||
nana::paint::graphics dum_graph({ r.width, r.height });
|
|
||||||
|
|
||||||
dum_graph.bitblt(r, graph, pos);
|
|
||||||
|
|
||||||
#ifdef _nana_std_has_string_view
|
|
||||||
dum_graph.string({}, { i.begin, len }, graph.palette(true));
|
|
||||||
#else
|
|
||||||
dum_graph.palette(true, graph.palette(true));
|
|
||||||
dum_graph.string({}, i.begin, len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
r.x = pos.x;
|
|
||||||
r.y = top;
|
|
||||||
graph.bitblt(r, dum_graph);
|
|
||||||
if(omitted_pixels)
|
|
||||||
detail::draw_string(dw, point{ endpos, top }, L"...", 3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pixels;
|
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
graphics& graph_;
|
||||||
|
const int left_, right_; //the range of rendering area in x-axis
|
||||||
|
const align text_align_;
|
||||||
|
unsigned ellipsis_px_{ 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -380,16 +339,10 @@ namespace nana
|
|||||||
|
|
||||||
static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf)
|
static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf)
|
||||||
{
|
{
|
||||||
unsigned acc_width = 0;
|
for (std::size_t i = begin; i < end; ++i)
|
||||||
for(std::size_t i = begin; i < end; ++i)
|
|
||||||
{
|
{
|
||||||
if(x + static_cast<int>(acc_width + pxbuf[i]) > endpos)
|
if ((x += static_cast<int>(pxbuf[i])) > endpos)
|
||||||
{
|
return (begin == i ? i + 1 : i);
|
||||||
if(i == begin)
|
|
||||||
++i;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
acc_width += pxbuf[i];
|
|
||||||
}
|
}
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
@@ -399,12 +352,11 @@ namespace nana
|
|||||||
wchar_t ch = str[index];
|
wchar_t ch = str[index];
|
||||||
if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
|
if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
|
||||||
{
|
{
|
||||||
wchar_t prch;
|
|
||||||
if(index)
|
if(index)
|
||||||
{
|
{
|
||||||
prch = str[index - 1];
|
auto prch = str[index - 1];
|
||||||
if('0' <= ch && ch <= '9')
|
if('0' <= ch && ch <= '9')
|
||||||
return !(('0' <= prch && prch <= '9') || (str[index - 1] == '-'));
|
return !(('0' <= prch && prch <= '9') || (prch == '-'));
|
||||||
|
|
||||||
return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A'));
|
return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A'));
|
||||||
}
|
}
|
||||||
@@ -481,6 +433,7 @@ namespace nana
|
|||||||
{
|
{
|
||||||
for(std::size_t i = idx_head; i < len; ++i)
|
for(std::size_t i = idx_head; i < len; ++i)
|
||||||
xpos += static_cast<int>(pxbuf[i]);
|
xpos += static_cast<int>(pxbuf[i]);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Check the word whether it is splittable.
|
//Check the word whether it is splittable.
|
||||||
@@ -585,8 +538,8 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if (graph_)
|
if (graph_)
|
||||||
{
|
{
|
||||||
helper::draw_string ds(graph_.handle(), pos.x, static_cast<int>(graph_.width()), text_align_);
|
helper::string_drawer sd{ graph_, pos.x, static_cast<int>(graph_.width()), text_align_, false };
|
||||||
helper::for_each_line(str, len, pos.y, ds);
|
helper::for_each_line(str, len, pos.y, sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,8 +547,8 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if (graph_)
|
if (graph_)
|
||||||
{
|
{
|
||||||
helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), omitted);
|
helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), text_align_, omitted };
|
||||||
helper::for_each_line(str, len, pos.y, dso);
|
helper::for_each_line(str, len, pos.y, sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user