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 }
0153 virtual void search(search_action& a_action) {
0154 if(touched()) {
0155 update_sg();
0156 reset_touched();
0157 }
0158 parent::search(a_action);
0159 if(a_action.done()) return;
0160 if(a_action.do_path()) a_action.path_push(this);
0161 if(back_visible.value()) {
0162 m_back_sep.search(a_action);
0163 if(a_action.done()) return;
0164 }
0165 m_sep.search(a_action);
0166 if(a_action.done()) return;
0167 if(a_action.do_path()) a_action.path_pop();
0168 }
0169 virtual void bbox(bbox_action& a_action) {
0170 if(touched()) {
0171 update_sg();
0172 reset_touched();
0173 }
0174 if(back_visible.value()) m_back_sep.bbox(a_action);
0175 m_sep.bbox(a_action);
0176 }
0177 public:
0178 text(const base_freetype& a_ttf)
0179 :parent()
0180 ,strings()
0181 ,confine(false)
0182
0183 ,color(colorf_black())
0184 ,font(font_hershey())
0185 ,font_modeling(font_filled)
0186 ,encoding(encoding_PAW())
0187 ,line_width(1)
0188 ,front_face(winding_ccw)
0189
0190 ,back_visible(true)
0191
0192 ,enforce_front_height(false)
0193 ,front_height(1)
0194 ,enforce_front_width(false)
0195 ,front_width(1)
0196
0197 ,wmargin_factor(0.9f)
0198 ,hmargin_factor(0.9f)
0199 ,hjust(left) // same default as base_text.
0200 ,vjust(middle) // not same default as base_text (which is bottom). We take middle for backcomp of confined text.
0201 // Note that text_hershey, text_freetype is (left,bottom) justified.
0202
0203 ,m_base_text(0)
0204 ,m_TT_text(base_freetype::create(a_ttf))
0205 {
0206 add_fields();
0207 }
0208 virtual ~text(){
0209 delete m_TT_text;
0210 }
0211 public:
0212 text(const text& a_from)
0213 :parent(a_from)
0214 ,strings(a_from.strings)
0215 ,confine(a_from.confine)
0216
0217 ,color(a_from.color)
0218 ,font(a_from.font)
0219 ,font_modeling(a_from.font_modeling)
0220 ,encoding(a_from.encoding)
0221 ,line_width(a_from.line_width)
0222 ,front_face(a_from.front_face)
0223
0224 ,back_visible(a_from.back_visible)
0225
0226 ,enforce_front_height(a_from.enforce_front_height)
0227 ,front_height(a_from.front_height)
0228 ,enforce_front_width(a_from.enforce_front_width)
0229 ,front_width(a_from.front_width)
0230
0231 ,wmargin_factor(a_from.wmargin_factor)
0232 ,hmargin_factor(a_from.hmargin_factor)
0233 ,hjust(a_from.hjust)
0234 ,vjust(a_from.vjust)
0235
0236 ,m_base_text(0)
0237 ,m_TT_text(base_freetype::create(*a_from.m_TT_text))
0238 {
0239 add_fields();
0240 }
0241 text& operator=(const text& a_from){
0242 parent::operator=(a_from);
0243 if(&a_from==this) return *this;
0244
0245 strings = a_from.strings;
0246 confine = a_from.confine;
0247
0248 color = a_from.color;
0249 font = a_from.font;
0250 font_modeling = a_from.font_modeling;
0251 encoding = a_from.encoding;
0252 line_width = a_from.line_width;
0253 front_face = a_from.front_face;
0254
0255 back_visible = a_from.back_visible;
0256
0257 enforce_front_height = a_from.enforce_front_height;
0258 front_height = a_from.front_height;
0259 enforce_front_width = a_from.enforce_front_width;
0260 front_width = a_from.front_width;
0261
0262 wmargin_factor = a_from.wmargin_factor;
0263 hmargin_factor = a_from.hmargin_factor;
0264 hjust = a_from.hjust;
0265 vjust = a_from.vjust;
0266
0267 m_base_text = 0;
0268 return *this;
0269 }
0270 public:
0271 float text_height() const {
0272 if(!m_base_text) return 0;
0273 return m_base_text->height;
0274 }
0275
0276 bool is_empty() const {
0277 tools_vforcit(std::string,strings.values(),it) {
0278 const std::string& line = *it;
0279 if(line.size()) return false;
0280 }
0281 return true;
0282 }
0283
0284 const separator& container() const {return m_back_sep;} //must be consistent with pick().
0285 public:
0286 void update_sg() {
0287 parent::update_sg();
0288
0289 m_sep.clear();
0290 m_base_text = 0;
0291
0292 if(width.value()<=0) return;
0293 if(height.value()<=0) return;
0294 if(is_empty()) return;
0295
0296 rgba* mat = new rgba();
0297 mat->color = color;
0298 m_sep.add(mat);
0299
0300 matrix* tsf = new matrix;
0301 m_sep.add(tsf);
0302
0303 float zz = back_visible.value()?0.01f:0;
0304
0305 if(font==font_hershey()) {
0306
0307 draw_style* ds = new draw_style;
0308 ds->style = draw_lines;
0309 ds->line_width = line_width;
0310 m_sep.add(ds);
0311
0312 text_hershey* _text = new text_hershey;
0313 m_base_text = _text;
0314 _text->encoding = encoding;
0315 _text->strings = strings;
0316 m_sep.add(_text);
0317
0318 } else {
0319
0320 m_base_text = m_TT_text;
0321 //ttf/arialbd 11
0322 //01234567890
0323 m_TT_text->font = font;
0324 m_TT_text->strings = strings;
0325 m_TT_text->modeling = font_modeling;
0326
0327 m_sep.add(new noderef(*m_TT_text));
0328
0329 }
0330
0331 if(enforce_front_height) {
0332
0333 m_base_text->height = front_height;
0334
0335 float mn_x,mn_y,mn_z;
0336 float mx_x,mx_y,mx_z;
0337 m_base_text->get_bounds(front_height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0338
0339 float bxw = mx_x-mn_x;
0340 float xtrans = 0;
0341 if(hjust==center) {
0342 xtrans = 0;
0343 } else if(hjust==left) {
0344 xtrans = bxw*0.5f;
0345 } else if(hjust==right) {
0346 xtrans = -bxw*0.5f;
0347 }
0348
0349 float bxh = mx_y-mn_y;
0350 float ytrans = 0;
0351 if(vjust==middle) {
0352 ytrans = 0;
0353 } else if(vjust==bottom) {
0354 ytrans = bxh*0.5f;
0355 } else if(vjust==top) {
0356 ytrans = -bxh*0.5f;
0357 }
0358
0359 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0360 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0361 tsf->set_translate(xx,yy,zz);
0362 return;
0363 }
0364
0365 if(enforce_front_width) {
0366
0367 float fh = height * hmargin_factor;
0368
0369 float th = fh;
0370 float mn_x,mn_y,mn_z;
0371 float mx_x,mx_y,mx_z;
0372 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0373 float bxw = mx_x-mn_x;
0374
0375 // adjust box width :
0376 // th -> bxw then to have front_width:
0377 if(bxw>0) {
0378 th = th*front_width/bxw;
0379 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0380 }
0381
0382 bxw = mx_x-mn_x;
0383 float xtrans = 0;
0384 if(hjust==center) {
0385 xtrans = 0;
0386 } else if(hjust==left) {
0387 xtrans = bxw*0.5f;
0388 } else if(hjust==right) {
0389 xtrans = -bxw*0.5f;
0390 }
0391
0392 float bxh = mx_y-mn_y;
0393 float ytrans = 0;
0394 if(vjust==middle) {
0395 ytrans = 0;
0396 } else if(vjust==bottom) {
0397 ytrans = bxh*0.5f;
0398 } else if(vjust==top) {
0399 ytrans = -bxh*0.5f;
0400 }
0401
0402 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0403 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0404 tsf->set_translate(xx,yy,zz);
0405
0406 m_base_text->height = bxh; //=th?
0407 return;
0408 }
0409
0410 //various automatic text height strategies :
0411 float fw = width * wmargin_factor;
0412 float fh = height * hmargin_factor;
0413
0414 if(confine) {
0415 // code common to freetype and hershey :
0416
0417 // try to adjust text within fw x fh (by attempting to be smart !).
0418 // the below assumes that text bounds are linear according
0419 // "text height".
0420 {float mn_x,mn_y,mn_z;
0421 float mx_x,mx_y,mx_z;
0422
0423 float th = fh;
0424 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0425 float bxh = mx_y-mn_y;
0426 // adjust box height :
0427 // fh -> bxh then to have fh :
0428 if(bxh>0) {
0429 th = fh*fh/bxh;
0430 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0431 }
0432
0433 //float bxw = box.mx()[0]-box.mn()[0];
0434 float bxw = mx_x-mn_x;
0435 bxh = mx_y-mn_y;
0436 if((fh>0)&&(bxh>0)){
0437 float fasp = fw/fh;
0438 float basp = bxw/bxh;
0439 if(fasp>=basp) {
0440 } else {
0441 // adjust box width :
0442 // th -> bxw then to have fw :
0443 if(bxw>0) {
0444 th = th*fw/bxw;
0445 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0446 }
0447 }
0448 }
0449
0450 m_base_text->height = th;
0451
0452 //bxw = box.mx()[0]-box.mn()[0];
0453 bxw = mx_x-mn_x;
0454 float xtrans = 0;
0455 if(hjust==center) {
0456 xtrans = 0;
0457 } else if(hjust==left) {
0458 xtrans = -fw*0.5f+bxw*0.5f;
0459 } else if(hjust==right) {
0460 xtrans = fw*0.5f-bxw*0.5f;
0461 }
0462
0463 bxh = mx_y-mn_y;
0464 float ytrans = 0;
0465 if(vjust==middle) {
0466 ytrans = 0;
0467 } else if(vjust==bottom) {
0468 ytrans = -fh*0.5f+bxh*0.5f;
0469 } else if(vjust==top) {
0470 ytrans = fh*0.5f-bxh*0.5f;
0471 }
0472
0473 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0474 float yy = -(mn_y+mx_y)*0.5F+ytrans;
0475
0476 tsf->set_translate(xx,yy,zz);
0477
0478 }
0479
0480 } else {
0481
0482 // we arrange yy so that two aside texts
0483 // with same height will have their text base lines aligned.
0484 // The max height is given by ascent+descent (with descent>0).
0485 float th = fh;
0486
0487 float mxh = m_base_text->ascent(th)+
0488 m_base_text->y_advance(th)*(strings.size()-1)+
0489 m_base_text->descent(th);
0490
0491 if(mxh) th = fh*fh/mxh; //end/final height.
0492
0493 m_base_text->height = th; //then all chars will fit into th.
0494
0495 mxh = m_base_text->ascent(th)+
0496 m_base_text->y_advance(th)*(strings.size()-1)+
0497 m_base_text->descent(th);
0498
0499 float yy = -fh*0.5f+m_base_text->descent(th)+
0500 m_base_text->y_advance(th)*(strings.size()-1);
0501
0502 {float mn_x,mn_y,mn_z;
0503 float mx_x,mx_y,mx_z;
0504 m_base_text->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0505
0506 float bxw = mx_x-mn_x;
0507 float xtrans = 0;
0508 if(hjust==center) {
0509 xtrans = 0;
0510 } else if(hjust==left) {
0511 xtrans = -fw*0.5f+bxw*0.5f;
0512 } else if(hjust==right) {
0513 xtrans = fw*0.5f-bxw*0.5f;
0514 }
0515
0516 float xx = -(mn_x+mx_x)*0.5F+xtrans;
0517 tsf->set_translate(xx,yy,zz);}
0518
0519 // truncate text at right if out of border :
0520 {std::vector<std::string> labcut;
0521 tools_vforcit(std::string,strings.values(),it) {
0522 std::string scut;
0523 m_base_text->truncate(*it,th,fw,scut);
0524 labcut.push_back(std::move(scut));
0525 }
0526 m_base_text->strings = labcut;}
0527 }
0528 }
0529
0530 void map_back_area_to_text() {
0531 if(!m_base_text) return;
0532
0533 float mn_x,mn_y,mn_z;
0534 float mx_x,mx_y,mx_z;
0535 m_base_text->get_bounds(front_height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0536
0537 float bxw = mx_x-mn_x;
0538 float bxh = mx_y-mn_y;
0539 parent::width = bxw/wmargin_factor;
0540 parent::height = bxh/hmargin_factor;
0541 }
0542
0543 protected:
0544 separator m_sep;
0545 base_text* m_base_text;
0546 base_freetype* m_TT_text; //optimize : avoid too much freetype load font.
0547 };
0548
0549 }}
0550
0551 #endif