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 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