g4tools  5.4.0
text
Go to the documentation of this file.
1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
2 // See the file tools.license for terms.
3 
4 #ifndef tools_sg_text
5 #define tools_sg_text
6 
7 #include "nodekit"
8 #include "back_area"
9 
10 #include "matrix"
11 #include "text_hershey"
12 #include "base_freetype"
13 
14 #include "enums"
15 #include "rgba"
16 #include "noderef"
17 #include "mf"
18 
19 #include "../colorf"
20 #include "../S_STRING"
21 
22 namespace tools {
23 namespace sg {
24 
25 class text : public back_area {
27 public:
30 
34 
36  sf<float> line_width; // for text_hershey.
38 
40 
45 
50 public:
51  virtual const desc_fields& node_desc_fields() const {
53  static const desc_fields s_v(parent::node_desc_fields(),17, //WARNING : have the right count.
56 
58 
60  font_hershey().c_str(),
61  font_lato_regular_ttf().c_str(),
62  font_roboto_bold_ttf().c_str(),
63  font_arial_ttf().c_str(),
64  font_arialbd_ttf().c_str(),
65  font_timesbd_ttf().c_str(),
66  font_symbol_ttf().c_str(),
67  font_stixgeneral_otf().c_str(),
68  font_helvetica_ttf().c_str(),
69  font_times_roman_ttf().c_str()
71 
77 
80 
85 
87 
94 
100 
106  );
107  return s_v;
108  }
109 private:
110  void add_fields(){
111  add_field(&strings);
112  add_field(&confine);
113 
114  add_field(&color);
115  add_field(&font);
120 
122 
127 
130  add_field(&hjust);
131  add_field(&vjust);
132  }
133 public:
134  virtual void render(render_action& a_action) {
135  if(touched()) {
136  update_sg();
137  reset_touched();
138  }
139  if(back_visible.value()) m_back_sep.render(a_action);
140  m_sep.render(a_action);
141  }
142  virtual void pick(pick_action& a_action) {
143  if(touched()) {
144  update_sg();
145  reset_touched();
146  }
147  if(back_visible.value()) {
148  nodekit_pick(a_action,m_back_sep,this);
149  }
150  //m_sep.pick(a_action);
151  }
152  virtual void search(search_action& a_action) {
153  if(touched()) {
154  update_sg();
155  reset_touched();
156  }
157  parent::search(a_action);
158  if(a_action.done()) return;
159  if(a_action.do_path()) a_action.path_push(this);
160  if(back_visible.value()) {
161  m_back_sep.search(a_action);
162  if(a_action.done()) return;
163  }
164  m_sep.search(a_action);
165  if(a_action.done()) return;
166  if(a_action.do_path()) a_action.path_pop();
167  }
168  virtual void bbox(bbox_action& a_action) {
169  if(touched()) {
170  update_sg();
171  reset_touched();
172  }
173  if(back_visible.value()) m_back_sep.bbox(a_action);
174  m_sep.bbox(a_action);
175  }
176 public:
177  text(const base_freetype& a_ttf)
178  :parent()
179  ,strings()
180  ,confine(false)
181 
182  ,color(colorf_black())
183  ,font(font_hershey())
186  ,line_width(1)
188 
189  ,back_visible(true)
190 
191  ,enforce_front_height(false)
192  ,front_height(1)
193  ,enforce_front_width(false)
194  ,front_width(1)
195 
196  ,wmargin_factor(0.9f)
197  ,hmargin_factor(0.9f)
198  ,hjust(left) // same default as base_text.
199  ,vjust(middle) // not same default as base_text (which is bottom). We take middle for backcomp of confined text.
200  // Note that text_hershey, text_freetype is (left,bottom) justified.
201 
202  ,m_base_text(0)
203  ,m_TT_text(base_freetype::create(a_ttf))
204  {
205  add_fields();
206  }
207  virtual ~text(){
208  delete m_TT_text;
209  }
210 public:
211  text(const text& a_from)
212  :parent(a_from)
213  ,strings(a_from.strings)
214  ,confine(a_from.confine)
215 
216  ,color(a_from.color)
217  ,font(a_from.font)
219  ,encoding(a_from.encoding)
220  ,line_width(a_from.line_width)
221  ,front_face(a_from.front_face)
222 
223  ,back_visible(a_from.back_visible)
224 
226  ,front_height(a_from.front_height)
228  ,front_width(a_from.front_width)
229 
232  ,hjust(a_from.hjust)
233  ,vjust(a_from.vjust)
234 
235  ,m_base_text(0)
237  {
238  add_fields();
239  }
240  text& operator=(const text& a_from){
241  parent::operator=(a_from);
242  if(&a_from==this) return *this;
243 
244  strings = a_from.strings;
245  confine = a_from.confine;
246 
247  color = a_from.color;
248  font = a_from.font;
249  font_modeling = a_from.font_modeling;
250  encoding = a_from.encoding;
251  line_width = a_from.line_width;
252  front_face = a_from.front_face;
253 
254  back_visible = a_from.back_visible;
255 
257  front_height = a_from.front_height;
259  front_width = a_from.front_width;
260 
263  hjust = a_from.hjust;
264  vjust = a_from.vjust;
265 
266  m_base_text = 0;
267 
268  //delete m_TT_text;
269  //m_TT_text = base_freetype::create(*a_from.m_TT_text);
270 
271  return *this;
272  }
273 public:
274  float text_height() const {
275  if(!m_base_text) return 0;
276  return m_base_text->height;
277  }
278 /*bool get_bounds(float a_height,
279  float& a_mn_x,float& a_mn_y,float& a_mn_z,
280  float& a_mx_x,float& a_mx_y,float& a_mx_z) const {
281  if(!m_base_text) {
282  a_mn_x = 0;
283  a_mn_y = 0;
284  a_mn_z = 0;
285  a_mx_x = 0;
286  a_mx_y = 0;
287  a_mx_z = 0;
288  return false;
289  }
290  m_base_text->get_bounds(m_base_text->height,a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z);
291  return true;
292  }*/
293  bool is_empty() const {
294  tools_vforcit(std::string,strings.values(),it) {
295  const std::string& line = *it;
296  if(line.size()) return false;
297  }
298  return true;
299  }
300 
301  const separator& container() const {return m_back_sep;} //must be consistent with pick().
302 public:
303  void update_sg() {
304  parent::update_sg();
305 
306  m_sep.clear();
307  m_base_text = 0;
308 
309  if(width.value()<=0) return;
310  if(height.value()<=0) return;
311  if(is_empty()) return;
312 
313  rgba* mat = new rgba();
314  mat->color = color;
315  m_sep.add(mat);
316 
317  matrix* tsf = new matrix;
318  m_sep.add(tsf);
319 
320  float fw = width * wmargin_factor;
321  float fh = height * hmargin_factor;
322 
323  //sf<float> zfront ?
324  float zz = back_visible.value()?0.01f:0;
325 
326  if(font==font_hershey()) {
327 
328  draw_style* ds = new draw_style;
329  ds->style = draw_lines;
330  ds->line_width = line_width;
331  m_sep.add(ds);
332 
333  text_hershey* _text = new text_hershey;
334  m_base_text = _text;
335  _text->encoding = encoding;
336  _text->strings = strings;
337  m_sep.add(_text);
338 
339  } else {
340 
342  //ttf/arialbd 11
343  //01234567890
344  m_TT_text->font = font;
347 
348  //_text->modeling.value(font_outline);
349 
350  m_sep.add(new noderef(*m_TT_text));
351 
352  }
353 
355 
357 
358  float mn_x,mn_y,mn_z;
359  float mx_x,mx_y,mx_z;
360  m_base_text->get_bounds(front_height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
361 
362  float bxw = mx_x-mn_x;
363  float xtrans = 0;
364  if(hjust==center) {
365  xtrans = 0;
366  } else if(hjust==left) {
367  xtrans = -fw*0.5f+bxw*0.5f;
368  } else if(hjust==right) {
369  xtrans = fw*0.5f-bxw*0.5f;
370  }
371 
372  float bxh = mx_y-mn_y;
373  float ytrans = 0;
374  if(vjust==middle) {
375  ytrans = 0;
376  } else if(vjust==bottom) {
377  ytrans = -fh*0.5f+bxh*0.5f;
378  } else if(vjust==top) {
379  ytrans = fh*0.5f-bxh*0.5f;
380  }
381 
382  float xx = -(mn_x+mx_x)*0.5F+xtrans;
383  float yy = -(mn_y+mx_y)*0.5F+ytrans;
384  tsf->set_translate(xx,yy,zz);
385 
386  return;
387  }
388 
389  if(enforce_front_width) {
390 
391  float th = fh;
392  float mn_x,mn_y,mn_z;
393  float mx_x,mx_y,mx_z;
394  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
395  float bxw = mx_x-mn_x;
396 
397  // adjust box width :
398  // th -> bxw then to have front_width:
399  if(bxw>0) {
400  th = th*front_width/bxw;
401  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
402  }
403 
404  bxw = mx_x-mn_x;
405  float xtrans = 0;
406  if(hjust==center) {
407  xtrans = 0;
408  } else if(hjust==left) {
409  xtrans = -fw*0.5f+bxw*0.5f;
410  } else if(hjust==right) {
411  xtrans = fw*0.5f-bxw*0.5f;
412  }
413 
414  float bxh = mx_y-mn_y;
415  float ytrans = 0;
416  if(vjust==middle) {
417  ytrans = 0;
418  } else if(vjust==bottom) {
419  ytrans = -fh*0.5f+bxh*0.5f;
420  } else if(vjust==top) {
421  ytrans = fh*0.5f-bxw*0.5f;
422  }
423 
424  float xx = -(mn_x+mx_x)*0.5F+xtrans;
425  float yy = -(mn_y+mx_y)*0.5F+ytrans;
426  tsf->set_translate(xx,yy,zz);
427 
428  m_base_text->height = bxh; //=th?
429 
430  return;
431  }
432 
433  //various automatic text height strategies :
434 
435  if(confine) {
436  // code common to freetype and hershey :
437 
438  // try to adjust text within fw x fh (by attempting to be smart !).
439  // the below assumes that text bounds are linear according
440  // "text height".
441  {float mn_x,mn_y,mn_z;
442  float mx_x,mx_y,mx_z;
443 
444  float th = fh;
445  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
446  float bxh = mx_y-mn_y;
447  // adjust box height :
448  // fh -> bxh then to have fh :
449  if(bxh>0) {
450  th = fh*fh/bxh;
451  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
452  }
453 
454  //float bxw = box.mx()[0]-box.mn()[0];
455  float bxw = mx_x-mn_x;
456  bxh = mx_y-mn_y;
457  if((fh>0)&&(bxh>0)){
458  float fasp = fw/fh;
459  float basp = bxw/bxh;
460  if(fasp>=basp) {
461  } else {
462  // adjust box width :
463  // th -> bxw then to have fw :
464  if(bxw>0) {
465  th = th*fw/bxw;
466  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
467  }
468  }
469  }
470 
471  m_base_text->height = th;
472 
473  //bxw = box.mx()[0]-box.mn()[0];
474  bxw = mx_x-mn_x;
475  float xtrans = 0;
476  if(hjust==center) {
477  xtrans = 0;
478  } else if(hjust==left) {
479  xtrans = -fw*0.5f+bxw*0.5f;
480  } else if(hjust==right) {
481  xtrans = fw*0.5f-bxw*0.5f;
482  }
483 
484  bxh = mx_y-mn_y;
485  float ytrans = 0;
486  if(vjust==middle) {
487  ytrans = 0;
488  } else if(vjust==bottom) {
489  ytrans = -fh*0.5f+bxh*0.5f;
490  } else if(vjust==top) {
491  ytrans = fh*0.5f-bxw*0.5f;
492  }
493 
494  float xx = -(mn_x+mx_x)*0.5F+xtrans;
495  float yy = -(mn_y+mx_y)*0.5F+ytrans;
496 
497  tsf->set_translate(xx,yy,zz);
498 
499  }
500 
501  } else {
502 
503  // we arrange yy so that two aside texts
504  // with same height will have their text base lines aligned.
505  // The max height is given by ascent+descent (with descent>0).
506  float th = fh;
507 
508  float mxh = m_base_text->ascent(th)+
509  m_base_text->y_advance(th)*(strings.size()-1)+
510  m_base_text->descent(th);
511 
512  //{box3f box;
513  // m_base_text->get_bounds(th,box);
514  // float bxh = box.mx()[1]-box.mn()[1]; //should be idem mxh.
515  // mxh = bxh;}
516 
517  if(mxh) th = fh*fh/mxh; //end/final height.
518 
519  m_base_text->height = th; //then all chars will fit into th.
520 
521  mxh = m_base_text->ascent(th)+
522  m_base_text->y_advance(th)*(strings.size()-1)+
523  m_base_text->descent(th);
524 
525  float yy = -fh*0.5f+m_base_text->descent(th)+
526  m_base_text->y_advance(th)*(strings.size()-1);
527 
528  //float xx = -fw*0.5F; //left justified.
529  //tsf->set_translate(xx,yy,zz);
530  {float mn_x,mn_y,mn_z;
531  float mx_x,mx_y,mx_z;
532  m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
533 
534  float bxw = mx_x-mn_x;
535  float xtrans = 0;
536  if(hjust==center) {
537  xtrans = 0;
538  } else if(hjust==left) {
539  xtrans = -fw*0.5f+bxw*0.5f;
540  } else if(hjust==right) {
541  xtrans = fw*0.5f-bxw*0.5f;
542  }
543 /*
544  float bxh = mx_y-mn_y;
545  float ytrans = 0;
546  if(vjust==middle) {
547  ytrans = 0;
548  } else if(vjust==bottom) {
549  ytrans = -fh*0.5f+bxh*0.5f;
550  } else if(vjust==top) {
551  ytrans = fh*0.5f-bxw*0.5f;
552  }
553 */
554  float xx = -(mn_x+mx_x)*0.5F+xtrans;
555  tsf->set_translate(xx,yy,zz);}
556 
557  // truncate text at right if out of border :
558  {std::vector<std::string> labcut;
559  tools_vforcit(std::string,strings.values(),it) {
560  std::string scut;
561  m_base_text->truncate(*it,th,fw,scut);
562  labcut.push_back(scut);
563  }
564  m_base_text->strings = labcut;}
565  }
566  }
567 
568 protected:
571  base_freetype* m_TT_text; //optimize : avoid too much freetype load font.
572 };
573 
574 }}
575 
576 #endif
tools::sg::text::vjust
sf_enum< sg::vjust > vjust
Definition: text:49
tools::dir::create
bool create(const std::string &a_name)
Definition: dir:53
tools::sg::text::confine
sf< bool > confine
Definition: text:29
tools::sg::font_pixmap
@ font_pixmap
Definition: enums:94
tools::sg::group::search
virtual void search(search_action &a_action)
Definition: group:51
tools::sg::base_text
Definition: base_text:17
tools::sg::text::bbox
virtual void bbox(bbox_action &a_action)
Definition: text:168
tools::sg::base_text::truncate
virtual bool truncate(const std::string &, float, float, std::string &) const =0
tools::sg::winding_ccw
@ winding_ccw
Definition: enums:105
TOOLS_ARG_FIELD_DESC_ENUMS_BEG
#define TOOLS_ARG_FIELD_DESC_ENUMS_BEG(a__field, a__num)
Definition: field:77
tools::sg::draw_style::line_width
sf< float > line_width
Definition: draw_style:22
tools::sg::base_text::height
sf< float > height
Definition: base_text:30
tools::sg::hjust
hjust
Definition: enums:73
tools::sg::text::font
sf_string font
Definition: text:32
tools::sg::base_freetype::modeling
sf_enum< font_modeling > modeling
Definition: base_freetype:21
tools::sg::text::m_TT_text
base_freetype * m_TT_text
Definition: text:571
tools::sg::bbox_action
Definition: bbox_action:15
tools::sg::matrix::set_translate
void set_translate(float a_x, float a_y, float a_z)
Definition: matrix:90
TOOLS_NODE
#define TOOLS_NODE(a__class, a__sclass, a__parent)
Definition: node:324
tools::sg::search_action::done
bool done() const
Definition: search_action:68
tools::sg::encoding_PAW
const std::string & encoding_PAW()
Definition: strings:42
tools::sg::rgba
Definition: rgba:16
mf
tools::sg::text
Definition: text:25
tools::sg::back_area::m_back_sep
separator m_back_sep
Definition: back_area:438
tools::sg::right
@ right
Definition: enums:76
tools::sg::base_freetype
Definition: base_freetype:16
tools::sg::base_text::descent
virtual float descent(float) const =0
tools::sg::text_hershey::encoding
sf_string encoding
Definition: text_hershey:86
tools::sg::base_text::get_bounds
virtual void get_bounds(float, float &, float &, float &, float &, float &, float &) const =0
tools::sg::draw_style
Definition: draw_style:18
tools::sg::text::color
sf_vec< colorf, float > color
Definition: text:31
tools::sg::search_action::path_push
void path_push(sg::node *a_v)
Definition: search_action:90
tools::sg::text::strings
mf_string strings
Definition: text:28
tools::sg::text_hershey
Definition: text_hershey:82
tools::sg::base_text::ascent
virtual float ascent(float) const =0
tools::sg::top
@ top
Definition: enums:82
tools::sg::desc_fields
Definition: field_desc:148
tools::sg::text::container
const separator & container() const
Definition: text:301
tools::sg::winding_cw
@ winding_cw
Definition: enums:106
tools::sg::color
Definition: color:16
tools::sg::text::hmargin_factor
sf< float > hmargin_factor
Definition: text:47
matrix
tools::sg::bmf::values
const std::vector< T > & values() const
Definition: bmf:71
tools::sg::pick_action
Definition: pick_action:59
tools::sg::separator::bbox
virtual void bbox(bbox_action &a_action)
Definition: separator:38
tools::sg::nodekit_pick
void nodekit_pick(pick_action &a_action, node &a_sg, node *a_node)
Definition: nodekit:13
tools::sg::text::enforce_front_width
sf< bool > enforce_front_width
Definition: text:43
tools::sg::text::m_base_text
base_text * m_base_text
Definition: text:570
tools::sg::left
@ left
Definition: enums:74
tools::sg::sf_vec
Definition: sf_vec:15
rgba
base_freetype
tools::sg::search_action::do_path
bool do_path() const
Definition: search_action:98
tools::sg::sf_enum< sg::font_modeling >
tools::sg::search_action::path_pop
void path_pop()
Definition: search_action:91
tools::sg::font_modeling
font_modeling
Definition: enums:91
tools::sg::group::add
void add(node *a_node)
Definition: group:96
tools::sg::text::line_width
sf< float > line_width
Definition: text:36
tools::sg::text::search
virtual void search(search_action &a_action)
Definition: text:152
tools::sg::base_freetype::font
sf_string font
Definition: base_freetype:19
tools::sg::text::update_sg
void update_sg()
Definition: text:303
tools::sg::text::font_modeling
sf_enum< sg::font_modeling > font_modeling
Definition: text:33
tools::sg::text::operator=
text & operator=(const text &a_from)
Definition: text:240
tools::sg::font_outline
@ font_outline
Definition: enums:92
TOOLS_ARG_FIELD_DESC_OPTS_BEG
#define TOOLS_ARG_FIELD_DESC_OPTS_BEG(a__field, a__num)
Definition: field:87
tools::sg::text::front_face
sf_enum< winding_type > front_face
Definition: text:37
tools::sg::search_action
Definition: search_action:19
tools::sg::back_area::height
sf< float > height
Definition: back_area:31
tools::sg::vjust
vjust
Definition: enums:79
tools::sg::render_action
Definition: render_action:24
tools::sg::separator
Definition: separator:15
tools::sg::text::~text
virtual ~text()
Definition: text:207
tools::sg::bottom
@ bottom
Definition: enums:80
TOOLS_ARG_FIELD_DESC_OPTS_END
#define TOOLS_ARG_FIELD_DESC_OPTS_END
Definition: field:89
tools::sg::middle
@ middle
Definition: enums:81
tools::sg::mf_string
Definition: mf:76
noderef
tools::sg::text::text
text(const base_freetype &a_ttf)
Definition: text:177
tools
inlined C code : ///////////////////////////////////
Definition: aida_ntuple:26
tools::sg::separator::render
virtual void render(render_action &a_action)
Definition: separator:18
tools::sg::node::add_field
void add_field(field *a_field)
Definition: node:128
tools::sg::matrix
Definition: matrix:19
tools::sg::text::m_sep
separator m_sep
Definition: text:569
tools::sg::text::enforce_front_height
sf< bool > enforce_front_height
Definition: text:41
enums
tools::sg::text::node_desc_fields
virtual const desc_fields & node_desc_fields() const
Definition: text:51
tools::sg::base_text::y_advance
virtual float y_advance(float) const =0
back_area
tools::sg::base_text::strings
mf_string strings
Definition: base_text:29
tools::sg::text::render
virtual void render(render_action &a_action)
Definition: text:134
TOOLS_FIELD_DESC_NODE_CLASS
#define TOOLS_FIELD_DESC_NODE_CLASS(a__class)
Definition: field:68
tools::mat
Definition: mat:19
tools::sg::text::hjust
sf_enum< sg::hjust > hjust
Definition: text:48
tools::sg::text::front_height
sf< float > front_height
Definition: text:42
TOOLS_ARG_ENUM
#define TOOLS_ARG_ENUM(a__value)
Definition: field:85
tools::sg::back_area
Definition: back_area:19
tools::sg::text::text
text(const text &a_from)
Definition: text:211
tools::sg::group::clear
void clear()
Definition: group:235
tools::sg::sf_string
Definition: sf_string:15
tools::sg::text::is_empty
bool is_empty() const
Definition: text:293
tools::sg::noderef
Definition: noderef:14
tools::sg::text::text_height
float text_height() const
Definition: text:274
tools::sg::bsf::value
T & value()
Definition: bsf:98
nodekit
tools::line
Definition: line:13
tools::sg::bmf::size
size_t size() const
Definition: bmf:69
tools::sg::text::pick
virtual void pick(pick_action &a_action)
Definition: text:142
tools::sg::font_hershey
const std::string & font_hershey()
Definition: strings:186
tools::sg::back_area::width
sf< float > width
Definition: back_area:30
tools::sg::center
@ center
Definition: enums:75
tools_vforcit
#define tools_vforcit(a__T, a__v, a__it)
Definition: forit:7
tools::sg::text::front_width
sf< float > front_width
Definition: text:44
tools::sg::font_filled
@ font_filled
Definition: enums:93
text_hershey
tools::sg::draw_style::style
sf_enum< draw_type > style
Definition: draw_style:21
tools::sg::text::encoding
sf_string encoding
Definition: text:35
tools::sg::text::back_visible
sf< bool > back_visible
Definition: text:39
tools::sg::draw_lines
@ draw_lines
Definition: enums:192
tools::sg::node::touched
virtual bool touched()
Definition: node:96
tools::sg::sf< bool >
TOOLS_ARG_FIELD_DESC
#define TOOLS_ARG_FIELD_DESC(a__field)
Definition: field:71
tools::sg::text::wmargin_factor
sf< float > wmargin_factor
Definition: text:46
tools::sg::node::reset_touched
virtual void reset_touched()
Definition: node:102
TOOLS_ARG_FIELD_DESC_ENUMS_END
#define TOOLS_ARG_FIELD_DESC_ENUMS_END
Definition: field:83