refactor text_renderer
This commit is contained in:
parent
363953be20
commit
a8c269d108
@ -16,7 +16,7 @@ namespace nana
|
||||
auto const end = str + len;
|
||||
for(auto i = str; i != end; ++i)
|
||||
{
|
||||
if(*i == '\n')
|
||||
if('\n' == *i)
|
||||
{
|
||||
top += static_cast<int>(f(top, str, i - str));
|
||||
str = i + 1;
|
||||
@ -26,166 +26,125 @@ namespace nana
|
||||
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)
|
||||
: dw(dw), x(x), endpos(endpos), text_align(ta)
|
||||
{}
|
||||
class string_drawer
|
||||
{
|
||||
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)
|
||||
{
|
||||
auto const drawable = graph_.handle();
|
||||
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 };
|
||||
unsigned pixels = 0;
|
||||
string_px += word_sz.width;
|
||||
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:
|
||||
for(auto & ent : reordered)
|
||||
for (auto & ent : reordered)
|
||||
{
|
||||
std::size_t len = ent.end - ent.begin;
|
||||
nana::size ts = detail::text_extent_size(dw, ent.begin, len);
|
||||
if (pos.x + static_cast<int>(wdm->width) > 0)
|
||||
{
|
||||
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;
|
||||
|
||||
if(pos.x + static_cast<int>(ts.width) > 0)
|
||||
detail::draw_string(dw, pos, ent.begin, len);
|
||||
nana::rectangle r{ nana::size{ static_cast<unsigned>(right_ - ellipsis_px_) - pos.x, wdm->height } };
|
||||
|
||||
pos.x += static_cast<int>(ts.width);
|
||||
if(pos.x >= endpos)
|
||||
nana::paint::graphics dummy({ r.width, r.height });
|
||||
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;
|
||||
|
||||
++wdm;
|
||||
}
|
||||
break;
|
||||
case align::center:
|
||||
pos.x = (right_ - left_ - string_px) / 2;
|
||||
for (auto & ent : reordered)
|
||||
{
|
||||
unsigned lenpx = 0;
|
||||
std::unique_ptr<unsigned[]> entity_pxs(new unsigned[reordered.size()]);
|
||||
|
||||
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;
|
||||
}
|
||||
detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin);
|
||||
pos.x += (wdm++)->width;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
std::swap(pos.x, xend);
|
||||
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;
|
||||
}
|
||||
pos.x -= (wdm--)->width;
|
||||
detail::draw_string(drawable, pos, i->begin, i->end - i->begin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
return return_max_height;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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(i == begin)
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
acc_width += pxbuf[i];
|
||||
if ((x += static_cast<int>(pxbuf[i])) > endpos)
|
||||
return (begin == i ? i + 1 : i);
|
||||
}
|
||||
return end;
|
||||
}
|
||||
@ -399,12 +352,11 @@ namespace nana
|
||||
wchar_t ch = str[index];
|
||||
if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
|
||||
{
|
||||
wchar_t prch;
|
||||
if(index)
|
||||
{
|
||||
prch = str[index - 1];
|
||||
auto prch = str[index - 1];
|
||||
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'));
|
||||
}
|
||||
@ -481,6 +433,7 @@ namespace nana
|
||||
{
|
||||
for(std::size_t i = idx_head; i < len; ++i)
|
||||
xpos += static_cast<int>(pxbuf[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
//Check the word whether it is splittable.
|
||||
@ -585,8 +538,8 @@ namespace nana
|
||||
{
|
||||
if (graph_)
|
||||
{
|
||||
helper::draw_string ds(graph_.handle(), pos.x, static_cast<int>(graph_.width()), text_align_);
|
||||
helper::for_each_line(str, len, pos.y, ds);
|
||||
helper::string_drawer sd{ graph_, pos.x, static_cast<int>(graph_.width()), text_align_, false };
|
||||
helper::for_each_line(str, len, pos.y, sd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,8 +547,8 @@ namespace nana
|
||||
{
|
||||
if (graph_)
|
||||
{
|
||||
helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast<int>(restricted_pixels), omitted);
|
||||
helper::for_each_line(str, len, pos.y, dso);
|
||||
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, sd);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user