Files
geant4/source/analysis/g4tools/include/tools/sg/infos_box
T
2016-12-09 12:35:28 +01:00

446 lines
11 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_sg_infos_box
#define tools_sg_infos_box
//
// In z the scene is within [0,0.5]
//
#include "back_area"
#include "matrix"
#include "text_hershey"
#include "base_freetype"
#include "enums"
#include "../colorf"
namespace tools {
namespace sg {
class infos_box : public back_area {
TOOLS_NODE(infos_box,tools::sg::infos_box,back_area)
public:
mf_string lstrings;
mf_string rstrings;
sf<unsigned int> num_spaces; //in "number of one line height" unit.
sf_vec<colorf,float> color;
sf_string font;
sf_string encoding;
sf<float> line_width; // for text_hershey.
sf_enum<winding_type> front_face; //no more used.
sf<bool> back_visible;
sf<float> wmargin_factor;
sf<float> hmargin_factor;
sf_enum<hjust> lhjust;
sf_enum<hjust> rhjust;
sf<bool> confine;
public:
virtual const std::vector<field_desc>& node_fields() const {
TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::infos_box)
static std::vector<field_desc> s_v;
if(s_v.empty()) {
s_v = parent::node_fields();
TOOLS_ADD_FIELD_DESC(lstrings)
TOOLS_ADD_FIELD_DESC(rstrings)
TOOLS_ADD_FIELD_DESC(num_spaces)
TOOLS_ADD_FIELD_DESC(color)
TOOLS_ADD_FIELD_DESC(font)
TOOLS_ADD_FIELD_DESC(encoding);
TOOLS_ADD_FIELD_DESC(line_width)
TOOLS_ADD_FIELD_DESC(front_face)
TOOLS_ADD_FIELD_DESC(back_visible)
TOOLS_ADD_FIELD_DESC(wmargin_factor)
TOOLS_ADD_FIELD_DESC(hmargin_factor)
TOOLS_ADD_FIELD_DESC(lhjust)
TOOLS_ADD_FIELD_DESC(rhjust)
TOOLS_ADD_FIELD_DESC(confine)
}
return s_v;
}
private:
void add_fields(){
add_field(&lstrings);
add_field(&rstrings);
add_field(&num_spaces);
add_field(&color);
add_field(&font);
add_field(&encoding);
add_field(&line_width);
add_field(&front_face);
add_field(&back_visible);
add_field(&wmargin_factor);
add_field(&hmargin_factor);
add_field(&lhjust);
add_field(&rhjust);
add_field(&confine);
}
public:
virtual void render(render_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
if(back_visible.value()) m_back_sep.render(a_action);
m_sep.render(a_action);
}
virtual void pick(pick_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
if(back_visible.value()) {
m_back_sep.pick(a_action);
if(a_action.done()) return;
}
}
virtual void search(search_action& a_action) {
node::search(a_action);
if(a_action.done()) return;
if(touched()) {
update_sg();
reset_touched();
}
if(back_visible.value()) {
m_back_sep.search(a_action);
if(a_action.done()) return;
}
m_sep.search(a_action);
if(a_action.done()) return;
}
virtual bool write(write_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
if(back_visible.value()) if(!m_back_sep.write(a_action)) return false;
return m_sep.write(a_action);
}
virtual void bbox(bbox_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
if(back_visible.value()) m_back_sep.bbox(a_action);
m_sep.bbox(a_action);
}
public:
infos_box(const base_freetype& a_ttf)
:parent()
,lstrings()
,rstrings()
,num_spaces(4)
,color(colorf_black())
,font(font_hershey())
,encoding(encoding_PAW())
,line_width(1)
,front_face(winding_ccw)
,back_visible(true)
,wmargin_factor(0.9f)
,hmargin_factor(0.9f)
,lhjust(left)
,rhjust(right)
,confine(false)
,m_ttf(a_ttf)
{
add_fields();
}
virtual ~infos_box(){}
public:
infos_box(const infos_box& a_from)
:parent(a_from)
,lstrings(a_from.lstrings)
,rstrings(a_from.rstrings)
,num_spaces(a_from.num_spaces)
,color(a_from.color)
,font(a_from.font)
,encoding(a_from.encoding)
,line_width(a_from.line_width)
,front_face(a_from.front_face)
,back_visible(a_from.back_visible)
,wmargin_factor(a_from.wmargin_factor)
,hmargin_factor(a_from.hmargin_factor)
,lhjust(a_from.lhjust)
,rhjust(a_from.rhjust)
,confine(a_from.confine)
,m_ttf(a_from.m_ttf)
{
add_fields();
}
infos_box& operator=(const infos_box& a_from){
parent::operator=(a_from);
lstrings = a_from.lstrings;
rstrings = a_from.rstrings;
num_spaces = a_from.num_spaces;
color = a_from.color;
font = a_from.font;
encoding = a_from.encoding;
line_width = a_from.line_width;
front_face = a_from.front_face;
back_visible = a_from.back_visible;
wmargin_factor = a_from.wmargin_factor;
hmargin_factor = a_from.hmargin_factor;
lhjust = a_from.lhjust;
rhjust = a_from.rhjust;
confine = a_from.confine;
return *this;
}
public:
void update_sg() {
// have this method public in order to use it in plotter.
// This is so because infos_box::height is an output field
// needed in plotter to place the box.
m_back_sep.clear(); //back_area::update_sg done last.
m_sep.clear();
if(width.value()<=0) return;
if(confine) {
if(height.value()<=0) return;
}
{bool empty = true;
std::vector<std::string>::const_iterator it;
for(it=lstrings.values().begin();it!=lstrings.values().end();++it) {
if((*it).size()) {empty = false;break;}
}
if(empty){
for(it=rstrings.values().begin();it!=rstrings.values().end();++it) {
if((*it).size()) {empty = false;break;}
}
}
if(empty) return;}
rgba* mat = new rgba();
mat->color = color;
m_sep.add(mat);
if(font==font_hershey()) {
draw_style* ds = new draw_style;
ds->style.value(draw_style::lines);
//ds->line_pattern = line_pattern;
ds->line_width = line_width;
m_sep.add(ds);
}
////////////////////////////////////////////////////////////
/// left text //////////////////////////////////////////////
////////////////////////////////////////////////////////////
base_text* ltext = 0;
matrix* ltsf = 0;
{separator* sep = new separator;
m_sep.add(sep);
ltsf = new matrix;
sep->add(ltsf);
if(font==font_hershey()) {
text_hershey* text = new text_hershey;
ltext = text;
text->encoding = encoding;
sep->add(text);
} else {
base_freetype* text = base_freetype::create(m_ttf);
//TTNODE* text = new TTNODE;
ltext = text;
text->font = font;
sep->add(text);
}
ltext->strings = lstrings;
ltext->hjust = lhjust;}
////////////////////////////////////////////////////////////
/// right text /////////////////////////////////////////////
////////////////////////////////////////////////////////////
base_text* rtext = 0;
matrix* rtsf = 0;
{separator* sep = new separator;
m_sep.add(sep);
rtsf = new matrix;
sep->add(rtsf);
if(font==font_hershey()) {
text_hershey* text = new text_hershey;
rtext = text;
text->encoding = encoding;
sep->add(text);
} else {
base_freetype* text = base_freetype::create(m_ttf);
//TTNODE* text = new TTNODE;
rtext = text;
text->font = font;
sep->add(text);
}
rtext->strings = rstrings;
rtext->hjust = rhjust;}
////////////////////////////////////////////////////////////
/// middle spaces //////////////////////////////////////////
////////////////////////////////////////////////////////////
base_text* mtext = 0;
{std::string s(num_spaces,' ');
if(font==font_hershey()) {
text_hershey* text = new text_hershey;
mtext = text;
text->strings.add(s);
text->hjust = left;
} else {
base_freetype* text = base_freetype::create(m_ttf);
//TTNODE* text = new TTNODE;
mtext = text;
text->strings.add(s);
text->hjust = left;
text->font = font;
}}
//sf<float> zfront ?
float zz = back_visible.value()?0.01f:0;
float fw = width * wmargin_factor;
if(confine) {
// left right texts may overlap.
// adjust height :
float fh = height * hmargin_factor;
float th = fh;
{float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
ltext->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
float bxh = mx_y-mn_y;
// adjust box height :
// fh -> bxh then to have fh :
if(!bxh) {
m_sep.clear();
parent::update_sg();
delete mtext;
return;
}
th = fh*fh/bxh;}
ltext->height = th;
rtext->height = th;
{float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
ltext->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
float lw = mx_x-mn_x;
float xtrans = (fw-lw)*0.5f; //left justified
float xx = -(mn_x+mx_x)*0.5F-xtrans;
float yy = -(mn_y+mx_y)*0.5F;
ltsf->set_translate(xx,yy,zz);}
{float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
rtext->get_bounds(th,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
rtext->hjust = right;
float xx = fw*0.5f;
float yy = -(mn_y+mx_y)*0.5F;
rtsf->set_translate(xx,yy,zz);}
parent::update_sg();
} else {
// height of the info box is an output of the below.
// The input to compute the geometry is the width of the infos
// box, the left/right texts and the space between
// left/right texts.
// from a text height of th=1, and a left/right sep
// of num_spaces*th, get width of the box :
float th = 1;
float lmn_x,lmn_y,lmn_z;
float lmx_x,lmx_y,lmx_z;
ltext->get_bounds(th,lmn_x,lmn_y,lmn_z,lmx_x,lmx_y,lmx_z);
float lw = (lmx_x<lmn_x)?0:lmx_x-lmn_x;
float rmn_x,rmn_y,rmn_z;
float rmx_x,rmx_y,rmx_z;
rtext->get_bounds(th,rmn_x,rmn_y,rmn_z,rmx_x,rmx_y,rmx_z);
float rw = (rmx_x<rmn_x)?0:rmx_x-rmn_x;
float mmn_x,mmn_y,mmn_z;
float mmx_x,mmx_y,mmx_z;
mtext->get_bounds(th,mmn_x,mmn_y,mmn_z,mmx_x,mmx_y,mmx_z);
float mw = (mmx_x<mmn_x)?0:mmx_x-mmn_x;
float winfos = lw+mw+rw;
if(!winfos) {
m_sep.clear();
height = 1;
parent::update_sg();
delete mtext;
return;
}
// assuming that text size is linear relative
// to th, we get the th needed to match infos_box.width :
// th -> winfos then to have fw :
th = fw*th/winfos;
// place the left/right texts by rescaling them to
// the new th :
ltext->height = th;
ltext->get_bounds(th,lmn_x,lmn_y,lmn_z,lmx_x,lmx_y,lmx_z);
float hinfos = (lmx_x<lmn_x)?0:lmx_y-lmn_y;
float xx = -fw*0.5F; //left justified.
float ty = -ltext->ascent(th)+hinfos*0.5f;
ltsf->set_translate(xx,ty,zz);
rtext->height = th;
if(rtext->hjust==right) {
xx = fw*0.5F;
} else if(rtext->hjust==left) {
rtext->get_bounds(th,rmn_x,rmn_y,rmn_z,rmx_x,rmx_y,rmx_z);
rw = (rmx_x<rmn_x)?0:rmx_x-rmn_x;
xx = fw*0.5F-rw;
} else { //center
rtext->get_bounds(th,rmn_x,rmn_y,rmn_z,rmx_x,rmx_y,rmx_z);
rw = (rmx_x<rmn_x)?0:rmx_x-rmn_x;
xx = fw*0.5F-rw*0.5F;
}
rtsf->set_translate(xx,ty,zz);
// set infos_box.height :
height = hinfos/hmargin_factor;
//done last because of the upper height setup.
parent::update_sg();
}
delete mtext;
}
protected:
const base_freetype& m_ttf;
separator m_sep;
};
}}
#endif