Back to home page

EIC code displayed by LXR

 
 

    


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