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