Warning, /include/Geant4/tools/sg/text is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_sg_text
0005 #define tools_sg_text
0006
0007 #include "nodekit"
0008 #include "back_area"
0009
0010 #include "matrix"
0011 #include "text_hershey"
0012 #include "base_freetype"
0013
0014 #include "enums"
0015 #include "rgba"
0016 #include "noderef"
0017 #include "mf"
0018
0019 #include "../colorf"
0020 #include "../S_STRING"
0021
0022 #include <utility>
0023
0024 namespace tools {
0025 namespace sg {
0026
0027 class text : public back_area {
0028 TOOLS_NODE(text,tools::sg::text,back_area)
0029 public:
0030 mf_string strings;
0031 sf<bool> confine;
0032
0033 sf_vec<colorf,float> color;
0034 sf_string font;
0035 sf_enum<sg::font_modeling> font_modeling;
0036
0037 sf_string encoding;
0038 sf<float> line_width; // for text_hershey.
0039 sf_enum<winding_type> front_face; //no more used.
0040
0041 sf<bool> back_visible;
0042
0043 sf<bool> enforce_front_height;
0044 sf<float> front_height;
0045 sf<bool> enforce_front_width;
0046 sf<float> front_width;
0047
0048 sf<float> wmargin_factor;
0049 sf<float> hmargin_factor;
0050 sf_enum<sg::hjust> hjust;
0051 sf_enum<sg::vjust> vjust;
0052 public:
0053 virtual const desc_fields& node_desc_fields() const {
0054 TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::text)
0055 static const desc_fields s_v(parent::node_desc_fields(),17, //WARNING : have the right count.
0056 TOOLS_ARG_FIELD_DESC(strings),
0057 TOOLS_ARG_FIELD_DESC(confine),
0058
0059 TOOLS_ARG_FIELD_DESC(color),
0060
0061 TOOLS_ARG_FIELD_DESC_OPTS_BEG(font,10)
0062 font_hershey().c_str(),
0063 font_lato_regular_ttf().c_str(),
0064 font_roboto_bold_ttf().c_str(),
0065 font_arial_ttf().c_str(),
0066 font_arialbd_ttf().c_str(),
0067 font_timesbd_ttf().c_str(),
0068 font_symbol_ttf().c_str(),
0069 font_stixgeneral_otf().c_str(),
0070 font_helvetica_ttf().c_str(),
0071 font_times_roman_ttf().c_str()
0072 TOOLS_ARG_FIELD_DESC_OPTS_END,
0073
0074 TOOLS_ARG_FIELD_DESC_ENUMS_BEG(font_modeling,3)
0075 TOOLS_ARG_ENUM(font_outline),
0076 TOOLS_ARG_ENUM(font_filled),
0077 TOOLS_ARG_ENUM(font_pixmap)
0078 TOOLS_ARG_FIELD_DESC_ENUMS_END,
0079
0080 TOOLS_ARG_FIELD_DESC(encoding),
0081 TOOLS_ARG_FIELD_DESC(line_width),
0082
0083 TOOLS_ARG_FIELD_DESC_ENUMS_BEG(front_face,2)
0084 TOOLS_ARG_ENUM(winding_ccw),
0085 TOOLS_ARG_ENUM(winding_cw)
0086 TOOLS_ARG_FIELD_DESC_ENUMS_END,
0087
0088 TOOLS_ARG_FIELD_DESC(back_visible),
0089
0090 TOOLS_ARG_FIELD_DESC(enforce_front_height),
0091 TOOLS_ARG_FIELD_DESC(front_height),
0092 TOOLS_ARG_FIELD_DESC(enforce_front_width),
0093 TOOLS_ARG_FIELD_DESC(front_width),
0094 TOOLS_ARG_FIELD_DESC(wmargin_factor),
0095 TOOLS_ARG_FIELD_DESC(hmargin_factor),
0096
0097 TOOLS_ARG_FIELD_DESC_ENUMS_BEG(hjust,3)
0098 TOOLS_ARG_ENUM(left),
0099 TOOLS_ARG_ENUM(center),
0100 TOOLS_ARG_ENUM(right)
0101 TOOLS_ARG_FIELD_DESC_ENUMS_END,
0102
0103 TOOLS_ARG_FIELD_DESC_ENUMS_BEG(vjust,3)
0104 TOOLS_ARG_ENUM(bottom),
0105 TOOLS_ARG_ENUM(middle),
0106 TOOLS_ARG_ENUM(top)
0107 TOOLS_ARG_FIELD_DESC_ENUMS_END
0108 );
0109 return s_v;
0110 }
0111 private:
0112 void add_fields(){
0113 add_field(&strings);
0114 add_field(&confine);
0115
0116 add_field(&color);
0117 add_field(&font);
0118 add_field(&font_modeling);
0119 add_field(&encoding);
0120 add_field(&line_width);
0121 add_field(&front_face);
0122
0123 add_field(&back_visible);
0124
0125 add_field(&enforce_front_height);
0126 add_field(&front_height);
0127 add_field(&enforce_front_width);
0128 add_field(&front_width);
0129
0130 add_field(&wmargin_factor);
0131 add_field(&hmargin_factor);
0132 add_field(&hjust);
0133 add_field(&vjust);
0134 }
0135 public:
0136 virtual void render(render_action& a_action) {
0137 if(touched()) {
0138 update_sg();
0139 reset_touched();
0140 }
0141 if(back_visible.value()) m_back_sep.render(a_action);
0142 m_sep.render(a_action);
0143 }
0144 virtual void pick(pick_action& a_action) {
0145 if(touched()) {
0146 update_sg();
0147 reset_touched();
0148 }
0149 if(back_visible.value()) {
0150 nodekit_pick(a_action,m_back_sep,this);
0151 }
0152 //m_sep.pick(a_action);
0153 }
0154 virtual void search(search_action& a_action) {
0155 if(touched()) {
0156 update_sg();
0157 reset_touched();
0158 }
0159 parent::search(a_action);
0160 if(a_action.done()) return;
0161 if(a_action.do_path()) a_action.path_push(this);
0162 if(back_visible.value()) {
0163 m_back_sep.search(a_action);
0164 if(a_action.done()) return;
0165 }
0166 m_sep.search(a_action);
0167 if(a_action.done()) return;
0168 if(a_action.do_path()) a_action.path_pop();
0169 }
0170 virtual void bbox(bbox_action& a_action) {
0171 if(touched()) {
0172 update_sg();
0173 reset_touched();
0174 }
0175 if(back_visible.value()) m_back_sep.bbox(a_action);
0176 m_sep.bbox(a_action);
0177 }
0178 public:
0179 text(const base_freetype& a_ttf)
0180 :parent()
0181 ,strings()
0182 ,confine(false)
0183
0184 ,color(colorf_black())
0185 ,font(font_hershey())
0186 ,font_modeling(font_filled)
0187 ,encoding(encoding_PAW())
0188 ,line_width(1)
0189 ,front_face(winding_ccw)
0190
0191 ,back_visible(true)
0192
0193 ,enforce_front_height(false)
0194 ,front_height(1)
0195 ,enforce_front_width(false)
0196 ,front_width(1)
0197
0198 ,wmargin_factor(0.9f)
0199 ,hmargin_factor(0.9f)
0200 ,hjust(left) // same default as base_text.
0201 ,vjust(middle) // not same default as base_text (which is bottom). We take middle for backcomp of confined text.
0202 // Note that text_hershey, text_freetype is (left,bottom) justified.
0203
0204 ,m_base_text(0)
0205 ,m_TT_text(base_freetype::create(a_ttf))
0206 {
0207 add_fields();
0208 }
0209 virtual ~text(){
0210 delete m_TT_text;
0211 }
0212 public:
0213 text(const text& a_from)
0214 :parent(a_from)
0215 ,strings(a_from.strings)
0216 ,confine(a_from.confine)
0217
0218 ,color(a_from.color)
0219 ,font(a_from.font)
0220 ,font_modeling(a_from.font_modeling)
0221 ,encoding(a_from.encoding)
0222 ,line_width(a_from.line_width)
0223 ,front_face(a_from.front_face)
0224
0225 ,back_visible(a_from.back_visible)
0226
0227 ,enforce_front_height(a_from.enforce_front_height)
0228 ,front_height(a_from.front_height)
0229 ,enforce_front_width(a_from.enforce_front_width)
0230 ,front_width(a_from.front_width)
0231
0232 ,wmargin_factor(a_from.wmargin_factor)
0233 ,hmargin_factor(a_from.hmargin_factor)
0234 ,hjust(a_from.hjust)
0235 ,vjust(a_from.vjust)
0236
0237 ,m_base_text(0)
0238 ,m_TT_text(base_freetype::create(*a_from.m_TT_text))
0239 {
0240 add_fields();
0241 }
0242 text& operator=(const text& a_from){
0243 parent::operator=(a_from);
0244 if(&a_from==this) return *this;
0245
0246 strings = a_from.strings;
0247 confine = a_from.confine;
0248
0249 color = a_from.color;
0250 font = a_from.font;
0251 font_modeling = a_from.font_modeling;
0252 encoding = a_from.encoding;
0253 line_width = a_from.line_width;
0254 front_face = a_from.front_face;
0255
0256 back_visible = a_from.back_visible;
0257
0258 enforce_front_height = a_from.enforce_front_height;
0259 front_height = a_from.front_height;
0260 enforce_front_width = a_from.enforce_front_width;
0261 front_width = a_from.front_width;
0262
0263 wmargin_factor = a_from.wmargin_factor;
0264 hmargin_factor = a_from.hmargin_factor;
0265 hjust = a_from.hjust;
0266 vjust = a_from.vjust;
0267
0268 m_base_text = 0;
0269
0270 //delete m_TT_text;
0271 //m_TT_text = base_freetype::create(*a_from.m_TT_text);
0272
0273 return *this;
0274 }
0275 public:
0276 float text_height() const {
0277 if(!m_base_text) return 0;
0278 return m_base_text->height;
0279 }
0280 /*bool get_bounds(float a_height,
0281 float& a_mn_x,float& a_mn_y,float& a_mn_z,
0282 float& a_mx_x,float& a_mx_y,float& a_mx_z) const {
0283 if(!m_base_text) {
0284 a_mn_x = 0;
0285 a_mn_y = 0;
0286 a_mn_z = 0;
0287 a_mx_x = 0;
0288 a_mx_y = 0;
0289 a_mx_z = 0;
0290 return false;
0291 }
0292 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);
0293 return true;
0294 }*/
0295 bool is_empty() const {
0296 tools_vforcit(std::string,strings.values(),it) {
0297 const std::string& line = *it;
0298 if(line.size()) return false;
0299 }
0300 return true;
0301 }
0302
0303 const separator& container() const {return m_back_sep;} //must be consistent with pick().
0304 public:
0305 void update_sg() {
0306 parent::update_sg();
0307
0308 m_sep.clear();
0309 m_base_text = 0;
0310
0311 if(width.value()<=0) return;
0312 if(height.value()<=0) return;
0313 if(is_empty()) return;
0314
0315 rgba* mat = new rgba();
0316 mat->color = color;
0317 m_sep.add(mat);
0318
0319 matrix* tsf = new matrix;
0320 m_sep.add(tsf);
0321
0322 //sf<float> zfront ?
0323 float zz = back_visible.value()?0.01f:0;
0324
0325 if(font==font_hershey()) {
0326
0327 draw_style* ds = new draw_style;
0328 ds->style = draw_lines;
0329 ds->line_width = line_width;
0330 m_sep.add(ds);
0331
0332 text_hershey* _text = new text_hershey;
0333 m_base_text = _text;
0334 _text->encoding = encoding;
0335 _text->strings = strings;
0336 m_sep.add(_text);
0337
0338 } else {
0339
0340 m_base_text = m_TT_text;
0341 //ttf/arialbd 11
0342 //01234567890
0343 m_TT_text->font = font;
0344 m_TT_text->strings = strings;
0345 m_TT_text->modeling = font_modeling;
0346
0347 //_text->modeling.value(font_outline);
0348
0349 m_sep.add(new noderef(*m_TT_text));
0350
0351 }
0352
0353 if(enforce_front_height) {
0354
0355 m_base_text->height = front_height;
0356
0357 float mn_x,mn_y,mn_z;
0358 float mx_x,mx_y,mx_z;
0359 m_base_text->get_bounds(front_height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0360
0361 float bxw = mx_x-mn_x;
0362 float xtrans = 0;
0363 if(hjust==center) {
0364 xtrans = 0;
0365 } else if(hjust==left) {
0366 xtrans = bxw*0.5f;
0367 } else if(hjust==right) {
0368 xtrans = -bxw*0.5f;
0369 }
0370
0371 float bxh = mx_y-mn_y;
0372 float ytrans = 0;
0373 if(vjust==middle) {
0374 ytrans = 0;
0375 } else if(vjust==bottom) {
0376 ytrans = bxh*0.5f;
0377 } else if(vjust==top) {
0378 ytrans = -bxh*0.5f;
0379 }
0380
0381 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0382 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0383 tsf->set_translate(xx,yy,zz);
0384 return;
0385 }
0386
0387 if(enforce_front_width) {
0388
0389 float fh = height * hmargin_factor;
0390
0391 float th = fh;
0392 float mn_x,mn_y,mn_z;
0393 float mx_x,mx_y,mx_z;
0394 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0395 float bxw = mx_x-mn_x;
0396
0397 // adjust box width :
0398 // th -> bxw then to have front_width:
0399 if(bxw>0) {
0400 th = th*front_width/bxw;
0401 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0402 }
0403
0404 bxw = mx_x-mn_x;
0405 float xtrans = 0;
0406 if(hjust==center) {
0407 xtrans = 0;
0408 } else if(hjust==left) {
0409 xtrans = bxw*0.5f;
0410 } else if(hjust==right) {
0411 xtrans = -bxw*0.5f;
0412 }
0413
0414 float bxh = mx_y-mn_y;
0415 float ytrans = 0;
0416 if(vjust==middle) {
0417 ytrans = 0;
0418 } else if(vjust==bottom) {
0419 ytrans = bxh*0.5f;
0420 } else if(vjust==top) {
0421 ytrans = -bxh*0.5f;
0422 }
0423
0424 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0425 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0426 tsf->set_translate(xx,yy,zz);
0427
0428 m_base_text->height = bxh; //=th?
0429 return;
0430 }
0431
0432 //various automatic text height strategies :
0433 float fw = width * wmargin_factor;
0434 float fh = height * hmargin_factor;
0435
0436 if(confine) {
0437 // code common to freetype and hershey :
0438
0439 // try to adjust text within fw x fh (by attempting to be smart !).
0440 // the below assumes that text bounds are linear according
0441 // "text height".
0442 {float mn_x,mn_y,mn_z;
0443 float mx_x,mx_y,mx_z;
0444
0445 float th = fh;
0446 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0447 float bxh = mx_y-mn_y;
0448 // adjust box height :
0449 // fh -> bxh then to have fh :
0450 if(bxh>0) {
0451 th = fh*fh/bxh;
0452 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0453 }
0454
0455 //float bxw = box.mx()[0]-box.mn()[0];
0456 float bxw = mx_x-mn_x;
0457 bxh = mx_y-mn_y;
0458 if((fh>0)&&(bxh>0)){
0459 float fasp = fw/fh;
0460 float basp = bxw/bxh;
0461 if(fasp>=basp) {
0462 } else {
0463 // adjust box width :
0464 // th -> bxw then to have fw :
0465 if(bxw>0) {
0466 th = th*fw/bxw;
0467 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0468 }
0469 }
0470 }
0471
0472 m_base_text->height = th;
0473
0474 //bxw = box.mx()[0]-box.mn()[0];
0475 bxw = mx_x-mn_x;
0476 float xtrans = 0;
0477 if(hjust==center) {
0478 xtrans = 0;
0479 } else if(hjust==left) {
0480 xtrans = -fw*0.5f+bxw*0.5f;
0481 } else if(hjust==right) {
0482 xtrans = fw*0.5f-bxw*0.5f;
0483 }
0484
0485 bxh = mx_y-mn_y;
0486 float ytrans = 0;
0487 if(vjust==middle) {
0488 ytrans = 0;
0489 } else if(vjust==bottom) {
0490 ytrans = -fh*0.5f+bxh*0.5f;
0491 } else if(vjust==top) {
0492 ytrans = fh*0.5f-bxh*0.5f;
0493 }
0494
0495 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0496 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0497
0498 tsf->set_translate(xx,yy,zz);
0499
0500 }
0501
0502 } else {
0503
0504 // we arrange yy so that two aside texts
0505 // with same height will have their text base lines aligned.
0506 // The max height is given by ascent+descent (with descent>0).
0507 float th = fh;
0508
0509 float mxh = m_base_text->ascent(th)+
0510 m_base_text->y_advance(th)*(strings.size()-1)+
0511 m_base_text->descent(th);
0512
0513 //{box3f box;
0514 // m_base_text->get_bounds(th,box);
0515 // float bxh = box.mx()[1]-box.mn()[1]; //should be idem mxh.
0516 // mxh = bxh;}
0517
0518 if(mxh) th = fh*fh/mxh; //end/final height.
0519
0520 m_base_text->height = th; //then all chars will fit into th.
0521
0522 mxh = m_base_text->ascent(th)+
0523 m_base_text->y_advance(th)*(strings.size()-1)+
0524 m_base_text->descent(th);
0525
0526 float yy = -fh*0.5f+m_base_text->descent(th)+
0527 m_base_text->y_advance(th)*(strings.size()-1);
0528
0529 //float xx = -fw*0.5F; //left justified.
0530 //tsf->set_translate(xx,yy,zz);
0531 {float mn_x,mn_y,mn_z;
0532 float mx_x,mx_y,mx_z;
0533 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0534
0535 float bxw = mx_x-mn_x;
0536 float xtrans = 0;
0537 if(hjust==center) {
0538 xtrans = 0;
0539 } else if(hjust==left) {
0540 xtrans = -fw*0.5f+bxw*0.5f;
0541 } else if(hjust==right) {
0542 xtrans = fw*0.5f-bxw*0.5f;
0543 }
0544 /*
0545 float bxh = mx_y-mn_y;
0546 float ytrans = 0;
0547 if(vjust==middle) {
0548 ytrans = 0;
0549 } else if(vjust==bottom) {
0550 ytrans = -fh*0.5f+bxh*0.5f;
0551 } else if(vjust==top) {
0552 ytrans = fh*0.5f-bxh*0.5f;
0553 }
0554 */
0555 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0556 tsf->set_translate(xx,yy,zz);}
0557
0558 // truncate text at right if out of border :
0559 {std::vector<std::string> labcut;
0560 tools_vforcit(std::string,strings.values(),it) {
0561 std::string scut;
0562 m_base_text->truncate(*it,th,fw,scut);
0563 labcut.push_back(std::move(scut));
0564 }
0565 m_base_text->strings = labcut;}
0566 }
0567 }
0568
0569 void map_back_area_to_text() {
0570 if(!m_base_text) return;
0571
0572 float mn_x,mn_y,mn_z;
0573 float mx_x,mx_y,mx_z;
0574 m_base_text->get_bounds(front_height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0575
0576 float bxw = mx_x-mn_x;
0577 float bxh = mx_y-mn_y;
0578 parent::width = bxw/wmargin_factor;
0579 parent::height = bxh/hmargin_factor;
0580 }
0581
0582 protected:
0583 separator m_sep;
0584 base_text* m_base_text;
0585 base_freetype* m_TT_text; //optimize : avoid too much freetype load font.
0586 };
0587
0588 }}
0589
0590 #endif