// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_text_valop #define tools_sg_text_valop #include "base_text" #include "valop2sg" #include "nodekit" #include "base_freetype" #include "mnmx" #include "../nostream" namespace tools { namespace sg { class text_valop : public base_text { public: TOOLS_NODE(text_valop,tools::sg::text_valop,base_text) public: sf_string encoding; sf_string font; sf_enum font_modeling; public: virtual const desc_fields& node_desc_fields() const { TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::text_valop) static const desc_fields s_v(parent::node_desc_fields(),3, //WARNING : take care of count. TOOLS_ARG_FIELD_DESC(encoding), TOOLS_ARG_FIELD_DESC(font), TOOLS_ARG_FIELD_DESC_ENUMS_BEG(font_modeling,3) TOOLS_ARG_ENUM(font_outline), TOOLS_ARG_ENUM(font_filled), TOOLS_ARG_ENUM(font_pixmap) TOOLS_ARG_FIELD_DESC_ENUMS_END ); return s_v; } private: void add_fields(){ add_field(&encoding); add_field(&font); add_field(&font_modeling); } public: virtual void render(render_action& a_action) { if(touched()) { update_sg(a_action.out()); reset_touched(); } m_sep.render(a_action); } virtual void pick(pick_action& a_action) { if(touched()) { update_sg(a_action.out()); reset_touched(); } nodekit_pick(a_action,m_sep,this); } virtual void bbox(bbox_action& a_action) { if(touched()) { update_sg(a_action.out()); reset_touched(); } m_sep.bbox(a_action); } virtual void search(search_action& a_action) { if(touched()) { update_sg(a_action.out()); reset_touched(); } parent::search(a_action); if(a_action.done()) return; if(a_action.do_path()) a_action.path_push(this); m_sep.search(a_action); if(a_action.done()) return; if(a_action.do_path()) a_action.path_pop(); } public: text_valop(const base_freetype& a_ttf) :parent() ,encoding(encoding_none()) ,font(font_hershey()) ,font_modeling(font_filled) ,m_ttf(a_ttf) { add_fields(); } virtual ~text_valop(){} public: text_valop(const text_valop& a_from) :parent(a_from) ,encoding(a_from.encoding) ,font(a_from.font) ,font_modeling(a_from.font_modeling) ,m_ttf(a_from.m_ttf) { add_fields(); } text_valop& operator=(const text_valop& a_from){ parent::operator=(a_from); encoding = a_from.encoding; font = a_from.font; font_modeling = a_from.font_modeling; return *this; } public: //sg::base_text : virtual void get_bounds(float /*a_height*/, float& a_mn_x,float& a_mn_y,float& a_mn_z, float& a_mx_x,float& a_mx_y,float& a_mx_z) const { text_valop& self = const_cast(*this); if(self.touched()) { self.update_sg(self.m_out); self.reset_touched(); } vec3f mn,mx; mnmx(self.m_out,self.m_sep,mn,mx); a_mn_x = mn[0];a_mn_y = mn[1];a_mn_z = mn[2]; a_mx_x = mx[0];a_mx_y = mx[1];a_mx_z = mx[2]; } virtual float ascent(float) const {return 1;} virtual float y_advance(float) const {return 1;} virtual float descent(float) const {return 0;} virtual bool truncate(const std::string&,float,float,std::string&) const {return false;} protected: void update_sg(std::ostream& a_out) { m_sep.clear(); matrix* tsf = new matrix; m_sep.add(tsf); tools_vforcit(std::string,strings.values(),it) { valop* _valop = new valop(valop::STRING,*it); valop2sg v(a_out,m_sep,m_ttf); if(!v.visit(*_valop)) { a_out << "tools::sg::text_valop::upate_sg : valop2sg.visit() failed." << std::endl; m_sep.clear(); delete _valop; return; } delete _valop; } vec3f mn,mx; mnmx(a_out,m_sep,mn,mx); float h = mx[1]-mn[1]; if(!h) { a_out << "tools::sg::text_valop::upate_sg : valop has null height." << std::endl; m_sep.clear(); return; } float scale = height.value()/h; tsf->set_scale(scale,scale,1); } protected: const base_freetype& m_ttf; separator m_sep; nostream m_out; }; }} #endif