// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_plots #define tools_sg_plots #include "_switch" #include "matrix" #include "plotter" namespace tools { namespace sg { class plots : public node { TOOLS_NODE(plots,tools::sg::plots,node) public: sf width; sf height; sf cols; //must never be 0. sf rows; //must never be 0. sf view_border; //current plotter border sf plotter_scale; //scale factor applied to each plotter. sf border_visible; sf border_width; sf border_height; sf border_z; sf border_scale; sf_vec border_color; // for gopaw : sf left_margin; sf right_margin; sf top_margin; sf bottom_margin; sf horizontal_spacing; sf vertical_spacing; public: virtual const desc_fields& node_desc_fields() const { TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::plots) static const desc_fields s_v(parent::node_desc_fields(),18, //WARNING : take care of count. TOOLS_ARG_FIELD_DESC(width), //1 TOOLS_ARG_FIELD_DESC(height), TOOLS_ARG_FIELD_DESC(cols), TOOLS_ARG_FIELD_DESC(rows), TOOLS_ARG_FIELD_DESC(view_border), TOOLS_ARG_FIELD_DESC(plotter_scale), TOOLS_ARG_FIELD_DESC(border_visible), TOOLS_ARG_FIELD_DESC(border_width), TOOLS_ARG_FIELD_DESC(border_height), TOOLS_ARG_FIELD_DESC(border_z), //10 TOOLS_ARG_FIELD_DESC(border_scale), TOOLS_ARG_FIELD_DESC(border_color), TOOLS_ARG_FIELD_DESC(left_margin), TOOLS_ARG_FIELD_DESC(right_margin), TOOLS_ARG_FIELD_DESC(top_margin), TOOLS_ARG_FIELD_DESC(bottom_margin), TOOLS_ARG_FIELD_DESC(horizontal_spacing), TOOLS_ARG_FIELD_DESC(vertical_spacing) ); return s_v; } virtual bool touched() { if(parent::touched()) return true; if(m_sep.empty()) return true; if(m_extras.size()!=m_extras_sep.size()) return true; return false; } private: void add_fields(){ add_field(&width); add_field(&height); add_field(&cols); add_field(&rows); add_field(&view_border); add_field(&plotter_scale); add_field(&border_visible); add_field(&border_width); add_field(&border_height); add_field(&border_z); add_field(&border_scale); add_field(&border_color); add_field(&left_margin); add_field(&right_margin); add_field(&top_margin); add_field(&bottom_margin); add_field(&horizontal_spacing); add_field(&vertical_spacing); } private: static unsigned int MATRIX() {return 0;} static unsigned int BORDER() {return 1;} static unsigned int PLOTTER() {return 2;} typedef std::vector ptbs_t; typedef std::vector todels_t; typedef std::vector prims_t; public: virtual void render(render_action& a_action) { update_if_touched(); m_group.render(a_action); } virtual void pick(pick_action& a_action) { update_if_touched(); nodekit_pick(a_action,m_group,this); } virtual void search(search_action& a_action) { update_if_touched(); parent::search(a_action); if(a_action.done()) return; if(a_action.do_path()) a_action.path_push(this); m_group.search(a_action); if(a_action.done()) return; if(a_action.do_path()) a_action.path_pop(); } virtual void bbox(bbox_action& a_action) { update_if_touched(); m_group.bbox(a_action); } virtual void event(event_action& a_action) { update_if_touched(); m_group.event(a_action); if(a_action.done()) return; } virtual bool write(write_action& a_action) { update_if_touched(); return m_group.write(a_action); } public: plots(const base_freetype& a_ttf) :parent() ,width(1) ,height(1) ,cols(1) ,rows(1) ,view_border(true) ,plotter_scale(1) ,border_visible(false) ,border_width(0) ,border_height(0) ,border_z(0) ,border_scale(1) ,border_color(colorf_grey()) ,left_margin(0) ,right_margin(0) ,top_margin(0) ,bottom_margin(0) ,horizontal_spacing(0) ,vertical_spacing(0) ,m_ttf(a_ttf) ,m_current(0) ,m_extras() ,m_old_cols(0) ,m_old_rows(0) { add_fields(); init_sg(); } virtual ~plots() { } public: plots(const plots& a_from) :parent(a_from) ,width(a_from.width) ,height(a_from.height) ,cols(a_from.cols) ,rows(a_from.rows) ,view_border(a_from.view_border) ,plotter_scale(a_from.plotter_scale) ,border_visible(a_from.border_visible) ,border_width(a_from.border_width) ,border_height(a_from.border_height) ,border_z(a_from.border_z) ,border_scale(a_from.border_scale) ,border_color(a_from.border_color) ,left_margin(a_from.left_margin) ,right_margin(a_from.right_margin) ,top_margin(a_from.top_margin) ,bottom_margin(a_from.bottom_margin) ,horizontal_spacing(a_from.horizontal_spacing) ,vertical_spacing(a_from.vertical_spacing) ,m_ttf(a_from.m_ttf) ,m_current(a_from.m_current) ,m_extras(a_from.m_extras) ,m_old_cols(0) ,m_old_rows(0) ,m_origins(a_from.m_origins) ,m_sizes(a_from.m_sizes) ,m_extras_origins(a_from.m_extras_origins) ,m_extras_sizes(a_from.m_extras_sizes) { add_fields(); init_sg(); if(!copy_plotters(a_from)) {} } plots& operator=(const plots& a_from){ parent::operator=(a_from); if(&a_from==this) return *this; width = a_from.width; height = a_from.height; cols = a_from.cols; rows = a_from.rows; view_border = a_from.view_border; plotter_scale = a_from.plotter_scale; border_visible = a_from.border_visible; border_width = a_from.border_width; border_height = a_from.border_height; border_z = a_from.border_z; border_scale = a_from.border_scale; border_color = a_from.border_color; left_margin = a_from.left_margin; right_margin = a_from.right_margin; top_margin = a_from.top_margin; bottom_margin = a_from.bottom_margin; horizontal_spacing = a_from.horizontal_spacing; vertical_spacing = a_from.vertical_spacing; m_old_cols = 0; m_old_rows = 0; m_origins = a_from.m_origins; m_sizes = a_from.m_sizes; m_extras_origins = a_from.m_extras_origins; m_extras_sizes = a_from.m_extras_sizes; m_current = a_from.m_current; m_extras = a_from.m_extras; if(!copy_plotters(a_from)) {} return *this; } public: unsigned int number() const {return cols*rows;} unsigned int current_index() const {return m_current;} void adjust_size(unsigned int a_ww,unsigned int a_wh) { if(!a_ww||!a_wh) return; float aspect = float(a_ww)/float(a_wh); width = height * aspect; } const base_freetype& ttf() const {return m_ttf;} public: void clear() { update_if_touched(); {size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->clear(); }} tools_vforit(extra,m_extras,it) { separator* sep = (*it).m_sep; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->clear(); } } bool has_data() { update_if_touched(); {size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; if(_plotter->plottables().size()) return true; }} tools_vforit(extra,m_extras,it) { separator* sep = (*it).m_sep; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; if(_plotter->plottables().size()) return true; } return false; } void touch_plotters() { //used in exlib/geant4/session. update_if_touched(); {size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->touch(); }} tools_vforit(extra,m_extras,it) { separator* sep = (*it).m_sep; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->touch(); } } void next() { update_if_touched(); size_t _number = m_sep.size(); if(m_current>=(uint32(_number)-1)) { m_current = 0; } else { m_current++; } update_current_border(); } bool set_current_plotter(unsigned int a_index) { update_if_touched(); if(a_index>=m_sep.size()) return false; m_current = a_index; update_current_border(); return true; } bool set_current(plotter* a_plotter) { //for popup. update_if_touched(); size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; if(_plotter==a_plotter) { m_current = uint32(index); update_current_border(); return true; } } return false; } plotter& current_plotter() { update_if_touched(); separator* sep = (separator*)m_sep[m_current]; return *((plotter*)(*sep)[PLOTTER()]); } plotter* find_plotter(unsigned int a_index) { update_if_touched(); if(a_index>=m_sep.size()) return 0; separator* sep = (separator*)m_sep[a_index]; return (plotter*)(*sep)[PLOTTER()]; } void set_regions(unsigned int a_cols = 1,unsigned int a_rows = 1,bool a_transfer = false) { unsigned int oldn = cols*rows; std::vector ptbss; std::vector primss; std::vector tdlss; std::vector pls; if(a_transfer) { ptbss.resize(oldn); primss.resize(oldn); tdlss.resize(oldn); pls.resize(oldn,plotter(m_ttf)); for(unsigned int index=0;indextransfer_plottables(ptbss[index]); p->transfer_primitives(primss[index]); p->transfer_todels(tdlss[index]); pls[index] = *p; //to copy styles. } } cols = a_cols?a_cols:1; rows = a_rows?a_rows:1; if(view_border.value()) {view_border = (number()==1?false:true);} update_sg(); set_current_plotter(0); clear(); if(a_transfer) { //fill new plotters with old data : unsigned int num = min_of(oldn,cols*rows); for(unsigned int index=0;indexcopy_style(pls[index]); //it must not touch p width, height, depth. {const ptbs_t& ptbs = ptbss[index]; tools_vforcit(plottable*,ptbs,it) p->add_plottable(*it);} {const prims_t& prims = primss[index]; tools_vforcit(plotprim*,prims,it) p->add_primitive(*it);} {const todels_t& todels = tdlss[index]; tools_vforcit(node*,todels,it) p->add_node_todel(*it);} } } reset_touched(); } void current_to_one() { ptbs_t ptbs;current_plotter().transfer_plottables(ptbs); prims_t prims;current_plotter().transfer_primitives(prims); todels_t tdls;current_plotter().transfer_todels(tdls); plotter pl = current_plotter(); //to copy styles. set_regions(1,1,false); plotter& p = current_plotter(); p.copy_style(pl); //copy styles. {tools_vforcit(plottable*,ptbs,it) p.add_plottable(*it);} {tools_vforcit(plotprim*,prims,it) p.add_primitive(*it);} {tools_vforcit(node*,tdls,it) p.add_node_todel(*it);} } void plotters(std::vector& a_vec) { //a_vec do NOT get ownership of sg::plotter objects. Use in G4Analysis. a_vec.clear(); update_if_touched(); size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; a_vec.push_back(_plotter); } } ////////////////////////////////////////////////////////////////////// //// styling methods : /////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// void set_line_width(float a_line_width) { update_if_touched(); size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->bins_style(0).line_width = a_line_width; _plotter->inner_frame_style().line_width = a_line_width; _plotter->grid_style().line_width = a_line_width; _plotter->x_axis().line_style().width = a_line_width; _plotter->x_axis().ticks_style().width = a_line_width; _plotter->y_axis().line_style().width = a_line_width; _plotter->y_axis().ticks_style().width = a_line_width; _plotter->z_axis().line_style().width = a_line_width; _plotter->z_axis().ticks_style().width = a_line_width; _plotter->colormap_axis().line_style().width = a_line_width; _plotter->colormap_axis().ticks_style().width = a_line_width; // needed if font is hershey : _plotter->title_style().line_width = a_line_width; _plotter->infos_style().line_width = a_line_width; _plotter->title_box_style().line_width = a_line_width; _plotter->x_axis().labels_style().line_width = a_line_width; _plotter->x_axis().mag_style().line_width = a_line_width; _plotter->x_axis().title_style().line_width = a_line_width; _plotter->y_axis().labels_style().line_width = a_line_width; _plotter->y_axis().mag_style().line_width = a_line_width; _plotter->y_axis().title_style().line_width = a_line_width; _plotter->z_axis().labels_style().line_width = a_line_width; _plotter->z_axis().mag_style().line_width = a_line_width; _plotter->z_axis().title_style().line_width = a_line_width; _plotter->colormap_axis().labels_style().line_width = a_line_width; _plotter->colormap_axis().mag_style().line_width = a_line_width; _plotter->colormap_axis().title_style().line_width = a_line_width; } } void set_grids_visibility(bool a_visible = false) { update_if_touched(); size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->grid_style().visible = a_visible; } border_visible = true; } void adjust_scales(float a_plotter_scale = 1) { // Rescale some plotter parameters (for example margins) according to the number of plots. // We assume that these parameters had been set previously according to one plot per page. // Then this function must be applied after all the styles had been applied (because // a plotting style may set these parameters). float ww_wc = width.value(); float wh_wc = height.value(); float rw_wc = ww_wc/cols.value(); float rh_wc = wh_wc/rows.value(); float cooking = 1.2f; //if increased the data area is diminished. float wfac = (rw_wc/ww_wc)*cooking; float hfac = (rh_wc/wh_wc)*cooking; float label_cooking = 1.6f; //if increased the labels are bigger. if((cols.value()>=4)&&(cols.value()>rows.value())) label_cooking = 0.9f; float title_cooking = 1.1f; //extra title cooking. plotter_scale = a_plotter_scale; update_if_touched(); {size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->left_margin = _plotter->left_margin * wfac; _plotter->right_margin = _plotter->right_margin * wfac; _plotter->bottom_margin = _plotter->bottom_margin * hfac; _plotter->top_margin = _plotter->top_margin * hfac; _plotter->x_axis().tick_length = _plotter->x_axis().tick_length * wfac; _plotter->y_axis().tick_length = _plotter->y_axis().tick_length * hfac; _plotter->title_to_axis = _plotter->title_to_axis * hfac; _plotter->title_height = _plotter->title_height * hfac * title_cooking; _plotter->x_axis().label_height = _plotter->x_axis().label_height * hfac * label_cooking; _plotter->y_axis().label_height = _plotter->y_axis().label_height * hfac * label_cooking; }} } //gopaw: void configure_grid_PAW(unsigned int a_ww,unsigned int a_wh) { m_origins.clear(); m_sizes.clear(); float wvp = float(a_ww); //pixels. float hvp = float(a_wh); //pixels. if( (wvp<=0)||(hvp<=0)||(width.value()<=0)||(height.value()<=0) ) return; unsigned int _cols = cols.value(); unsigned int _rows = rows.value(); if((!_cols)||(!_rows)) return; float wdata = (width.value()-left_margin.value()-right_margin.value()-(_cols-1)*horizontal_spacing.value())/_cols; float hdata = (height.value()-bottom_margin.value()-top_margin.value()-(_rows-1)*vertical_spacing.value())/_rows; if((wdata<=0)||(hdata<=0)) return; unsigned int _num = number(); for(unsigned int iregion=0;iregion<_num;iregion++) { //iregion = col + row * cols unsigned int row = iregion/_cols; unsigned int col = iregion - row * _cols; float wr,hr,x,y,lm,rm,bm,tm; wr = hr = x = y = 0; lm = rm = bm = tm = 0; if(_cols==1) { wr = width.value(); x = 0; lm = left_margin.value(); rm = right_margin.value(); } else { float wrl = left_margin.value()+wdata+horizontal_spacing.value()/2; float wrr = right_margin.value()+wdata+horizontal_spacing.value()/2; float wri = wdata+horizontal_spacing.value(); if(col==0) { wr = wrl; x = 0; lm = left_margin.value(); rm = horizontal_spacing.value()/2; } else if(col==(_cols-1)) { wr = wrr; x = width.value() - wrr; lm = horizontal_spacing.value()/2; rm = right_margin.value(); } else { wr = wri; x = wrl + (col-1) * wri; lm = horizontal_spacing.value()/2; rm = horizontal_spacing.value()/2; } } if(_rows==1) { hr = height.value(); y = 0; tm = top_margin.value(); bm = bottom_margin.value(); } else { float hrt = top_margin.value()+hdata+vertical_spacing.value()/2; //top float hrb = bottom_margin.value()+hdata+vertical_spacing.value()/2; //bottom float hri = hdata+vertical_spacing.value(); if(row==0) { //top row. hr = hrt; y = height.value()-hrt; tm = top_margin.value(); bm = vertical_spacing.value()/2; } else if(row==(_rows-1)) { hr = hrb; y = 0; tm = vertical_spacing.value()/2; bm = bottom_margin.value(); } else { hr = hri; y = height.value()- (hrt + row * hri); tm = vertical_spacing.value()/2; bm = vertical_spacing.value()/2; } } m_origins.push_back(vec2f(x,y)); m_sizes.push_back(vec2f(wr,hr)); separator* sep = (separator*)m_sep[iregion]; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->left_margin = lm; _plotter->right_margin = rm; _plotter->top_margin = tm; _plotter->bottom_margin = bm; } } void configure_extras_PAW(unsigned int a_ww,unsigned int a_wh) { m_extras_origins.clear(); m_extras_sizes.clear(); float wvp = float(a_ww); //pixels. float hvp = float(a_wh); //pixels. if( (wvp<=0)||(hvp<=0)||(width.value()<=0)||(height.value()<=0) ) return; tools_vforcit(extra,m_extras,it) { const extra& _extra = *it; unsigned int _cols = _extra.m_cols; unsigned int _rows = _extra.m_rows; if((!_cols)||(!_rows)) continue; float wdata = (width.value()-left_margin.value()-right_margin.value()-(_cols-1)*horizontal_spacing.value())/_cols; float hdata = (height.value()-bottom_margin.value()-top_margin.value()-(_rows-1)*vertical_spacing.value())/_rows; if((wdata<=0)||(hdata<=0)) continue; unsigned int iregion = _extra.m_index; unsigned int row = iregion/_cols; unsigned int col = iregion - row * _cols; float wr,hr,x,y,lm,rm,bm,tm; wr = hr = x = y = 0; lm = rm = bm = tm = 0; if(_cols==1) { wr = width.value(); x = 0; lm = left_margin.value(); rm = right_margin.value(); } else { float wrl = left_margin.value()+wdata+horizontal_spacing.value()/2; float wrr = right_margin.value()+wdata+horizontal_spacing.value()/2; float wri = wdata+horizontal_spacing.value(); if(col==0) { wr = wrl; x = 0; lm = left_margin.value(); rm = horizontal_spacing.value()/2; } else if(col==(_cols-1)) { wr = wrr; x = width.value() - wrr; lm = horizontal_spacing.value()/2; rm = right_margin.value(); } else { wr = wri; x = wrl + (col-1) * wri; lm = horizontal_spacing.value()/2; rm = horizontal_spacing.value()/2; } } if(_rows==1) { hr = height.value(); y = 0; tm = top_margin.value(); bm = bottom_margin.value(); } else { float hrt = top_margin.value()+hdata+vertical_spacing.value()/2; //top float hrb = bottom_margin.value()+hdata+vertical_spacing.value()/2; //bottom float hri = hdata+vertical_spacing.value(); if(row==0) { //top row. hr = hrt; y = height.value()-hrt; tm = top_margin.value(); bm = vertical_spacing.value()/2; } else if(row==(_rows-1)) { hr = hrb; y = 0; tm = vertical_spacing.value()/2; bm = bottom_margin.value(); } else { hr = hri; y = height.value()- (hrt + row * hri); tm = vertical_spacing.value()/2; bm = vertical_spacing.value()/2; } } m_extras_origins.push_back(vec2f(x,y)); m_extras_sizes.push_back(vec2f(wr,hr)); separator* sep = _extra.m_sep; plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; _plotter->left_margin = lm; _plotter->right_margin = rm; _plotter->top_margin = tm; _plotter->bottom_margin = bm; } //tools_vforcit } void configure_PAW(unsigned int a_ww,unsigned int a_wh) { configure_grid_PAW(a_ww,a_wh); configure_extras_PAW(a_ww,a_wh); touch(); update_if_touched(); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// //gopaw: void delete_extras() { m_extras_sep.clear(); m_extras.clear(); } plotter* create_extra_plotter(unsigned int a_cols,unsigned int a_rows,unsigned int a_index) { // Create a plotter with size and position as if in a grid of a_colsxa_rows and at position a_index. // The index numbering being for example for a grid of 3x2 : // 0 1 2 // 3 4 5 m_extras.push_back(extra(a_cols,a_rows,a_index)); update_if_touched(); separator* sep = m_extras.back().m_sep; return (plotter*)(*sep)[PLOTTER()]; } plotter* last_extra_plotter() const { if(m_extras.empty()) return 0; separator* sep = m_extras.back().m_sep; return (plotter*)(*sep)[PLOTTER()]; } public: void init_sg() { // used also in gopaw::base_viewer::clean_gstos(). m_group.clear(); m_sep.clear(); m_border_sep.clear(); m_extras_sep.clear(); m_group.add(new noderef(m_sep)); m_group.add(new noderef(m_border_sep)); m_group.add(new noderef(m_extras_sep)); } void clear_sg() { //used in GL_plots_viewer. m_group.clear(); m_sep.clear(); m_border_sep.clear(); m_extras_sep.clear(); } protected: void update_if_touched() { if(touched()) { update_sg(); reset_touched(); } } void update_sg(){ if(m_sep.empty()||(cols.value()!=m_old_cols)||(rows.value()!=m_old_rows)){ m_old_cols = cols; m_old_rows = rows; m_sep.clear(); for(unsigned int irow=0;irowadd(new sg::matrix); //MATRIX() _switch* border = new _switch; sep->add(border); //BORDER() sep->add(new plotter(m_ttf)); //PLOTTER() } } if(m_current>=m_sep.size()) m_current = 0; } update_current_border(); update_border(); if((width.value()>0)&&(height.value()>0)) { size_t _number = m_sep.size(); bool configure = (m_origins.size()==_number)&&(m_sizes.size()==_number)?true:false; // all window wc : float ww_wc = width; float wh_wc = height; for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; set_plotter_layout(*sep,index,configure,cols.value(),rows.value(), ww_wc,wh_wc,m_origins,m_sizes,plotter_scale.value()); } } update_extras(); } bool copy_plotters(const plots& a_from) { update_if_touched(); if(m_sep.size()==a_from.m_sep.size()) { size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* _from_sep = (separator*)a_from.m_sep[index]; matrix* _from_matrix = (matrix*)(*_from_sep)[MATRIX()]; plotter* _from_plotter = (plotter*)(*_from_sep)[PLOTTER()]; separator* _sep = (separator*)m_sep[index]; matrix* _matrix = (matrix*)(*_sep)[MATRIX()]; plotter* _plotter = (plotter*)(*_sep)[PLOTTER()]; _matrix->operator=(*_from_matrix); _plotter->operator=(*_from_plotter); } } if(m_extras_sep.size()==a_from.m_extras_sep.size()) { size_t _number = m_extras_sep.size(); for(size_t index=0;index<_number;index++) { separator* _from_sep = (separator*)a_from.m_extras_sep[index]; matrix* _from_matrix = (matrix*)(*_from_sep)[MATRIX()]; plotter* _from_plotter = (plotter*)(*_from_sep)[PLOTTER()]; separator* _sep = (separator*)m_extras_sep[index]; matrix* _matrix = (matrix*)(*_sep)[MATRIX()]; plotter* _plotter = (plotter*)(*_sep)[PLOTTER()]; _matrix->operator=(*_from_matrix); _plotter->operator=(*_from_plotter); } } return true; } static void create_plotter_border(_switch& a_parent,float a_w,float a_h) { a_parent.clear(); group* sep = new group; a_parent.add(sep); a_parent.add(new group()); //empty rgba* mat = new rgba(); mat->color = colorf_red(); sep->add(mat); draw_style* ds = new draw_style; ds->style = draw_lines; ds->line_width = 4; sep->add(ds); vertices* vtxs = new vertices; vtxs->mode = gl::line_strip(); sep->add(vtxs); float dw = a_w*0.5f; float dh = a_h*0.5f; vtxs->add(-dw,-dh,0); vtxs->add( dw,-dh,0); vtxs->add( dw, dh,0); vtxs->add(-dw, dh,0); vtxs->add(-dw,-dh,0); } void update_current_border() { size_t _number = m_sep.size(); for(size_t index=0;index<_number;index++) { separator* sep = (separator*)m_sep[index]; _switch* _border = (_switch*)(*sep)[BORDER()]; if(index==m_current) { _border->which = view_border.value()?0:1; } else { _border->which = 1; } } } void update_border() { m_border_sep.clear(); if(!border_visible.value()) return; if(width.value()<=0) return; if(height.value()<=0) return; if(border_width.value()<=0) return; if(border_height.value()<=0) return; // border_scale could be used as an offscreen (inzb_[ps,png,jpeg], gl2s_pdf) // cooking to avoid seeing a one pixel line at some side (in general left) // coming from the border. if(border_scale.value()!=1) { matrix* _m = new matrix; _m->set_scale(border_scale.value(),border_scale.value(),1); m_border_sep.add(_m); } float bw = border_width; float bh = border_height; // do it with four externals back_area. float zz = border_z.value(); // top : {separator* sep = new separator; m_border_sep.add(sep); float wba = width+2*bw; float hba = bh; float x = 0; float y = height*0.5f+bh*0.5f; matrix* _m = new matrix; _m->set_translate(x,y,zz); sep->add(_m); back_area* b = new back_area; b->border_visible = false; b->color = border_color; b->width = wba; b->height = hba; sep->add(b);} // bottom : {separator* sep = new separator; m_border_sep.add(sep); float wba = width+2*bw; float hba = bh; float x = 0; float y = -height*0.5f-bh*0.5f; matrix* _m = new matrix; _m->set_translate(x,y,zz); sep->add(_m); back_area* b = new back_area; b->border_visible = false; b->color = border_color; b->width = wba; b->height = hba; sep->add(b);} // left : {separator* sep = new separator; m_border_sep.add(sep); float wba = bw; float hba = height+2*bh; float x = -width*0.5f-bw*0.5f; float y = 0; matrix* _m = new matrix; _m->set_translate(x,y,zz); sep->add(_m); back_area* b = new back_area; b->border_visible = false; b->color = border_color; b->width = wba; b->height = hba; sep->add(b);} // right : {separator* sep = new separator; m_border_sep.add(sep); float wba = bw; float hba = height+2*bh; float x = width*0.5f+bw*0.5f; float y = 0; matrix* _m = new matrix; _m->set_translate(x,y,zz); sep->add(_m); back_area* b = new back_area; b->border_visible = false; b->color = border_color; b->width = wba; b->height = hba; sep->add(b);} } protected: class extra { public: extra(unsigned int a_cols,unsigned int a_rows,unsigned int a_index) :m_cols(a_cols),m_rows(a_rows),m_index(a_index),m_sep(0){} virtual ~extra(){} public: extra(const extra& a_from):m_cols(a_from.m_cols),m_rows(a_from.m_rows),m_index(a_from.m_index),m_sep(0){} extra& operator=(const extra& a_from) { m_cols = a_from.m_cols; m_rows = a_from.m_rows; m_index = a_from.m_index; m_sep = a_from.m_sep; return *this; } public: unsigned int m_cols; unsigned int m_rows; unsigned int m_index; separator* m_sep; }; void update_extras() { if(m_extras.size()!=m_extras_sep.size()) { m_extras_sep.clear(); tools_vforit(extra,m_extras,it) { // same sg layout than grid plotters. separator* sep = new separator; m_extras_sep.add(sep); (*it).m_sep = sep; //*it does not get ownership. sep->add(new sg::matrix); //MATRIX() _switch* border = new _switch; sep->add(border); //BORDER() sep->add(new plotter(m_ttf)); //PLOTTER() } } if(width.value()<=0) return; if(height.value()<=0) return; // all window wc : float ww_wc = width; float wh_wc = height; size_t _number = m_extras.size(); bool configure = (m_extras_origins.size()==_number)&&(m_extras_sizes.size()==_number)?true:false; tools_vforcit(extra,m_extras,it) { const extra& _extra = *it; unsigned int index = _extra.m_index; if(index>=(m_extras_sep.size())) index = 0; separator* sep = _extra.m_sep; set_plotter_layout(*sep,index,configure,_extra.m_cols,_extra.m_rows, ww_wc,wh_wc,m_extras_origins,m_extras_sizes,plotter_scale.value()); } } protected: static void set_plotter_layout(separator& a_sep,size_t a_index,bool a_configure, unsigned int a_cols,unsigned int a_rows, float a_ww_wc,float a_wh_wc, const std::vector& a_origins,const std::vector& a_sizes,float a_scale) { size_t row = a_index/a_cols; size_t col = a_index-a_cols*row; float rw_wc = a_ww_wc/a_cols; float rh_wc = a_wh_wc/a_rows; matrix* _matrix = (matrix*)(a_sep)[MATRIX()]; plotter* _plotter = (plotter*)(a_sep)[PLOTTER()]; if(a_configure) { _plotter->width = a_sizes[a_index].x(); _plotter->height = a_sizes[a_index].y(); float x = -a_ww_wc*0.5f + a_origins[a_index].x() + _plotter->width*0.5f; float y = -a_wh_wc*0.5f + a_origins[a_index].y() + _plotter->height*0.5f; _matrix->set_translate(x,y,0); } else { float x = -a_ww_wc*0.5f + col * rw_wc + rw_wc * 0.5f; float y = a_wh_wc*0.5f - row * rh_wc - rh_wc * 0.5f; _matrix->set_translate(x,y,0); } _matrix->mul_scale(a_scale,a_scale,1); //applied first. {_switch* _border = (_switch*)(a_sep)[BORDER()]; create_plotter_border(*_border,rw_wc,rh_wc); _border->which = 1; } if(_plotter->shape.value()==plotter::xy) { _plotter->depth = min_of(rw_wc,rh_wc); } else { _plotter->depth = rh_wc; } if(a_configure) { } else { if(_plotter->shape.value()==plotter::xy) { _plotter->width = rw_wc; _plotter->height = rh_wc; } else { if((rw_wc/rh_wc)>=1.0f) { _plotter->width = rh_wc; _plotter->height = rh_wc; } else { _plotter->width = rw_wc; _plotter->height = rw_wc; } } } } protected: const base_freetype& m_ttf; group m_group; separator m_sep; separator m_border_sep; separator m_extras_sep; unsigned int m_current; std::vector m_extras; //updater* m_updater; unsigned int m_old_cols; unsigned int m_old_rows; std::vector m_origins; std::vector m_sizes; std::vector m_extras_origins; std::vector m_extras_sizes; }; }} #endif