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