572 lines
16 KiB
Plaintext
572 lines
16 KiB
Plaintext
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
|
// See the file tools.license for terms.
|
|
|
|
#ifndef tools_xml_styles
|
|
#define tools_xml_styles
|
|
|
|
#include "../vpair"
|
|
#include "../sg/style_colormap"
|
|
#include "../smatch"
|
|
#include "../sout"
|
|
#include "../forit"
|
|
#include "../sbeg"
|
|
|
|
namespace tools {
|
|
namespace xml {
|
|
|
|
class styles {
|
|
public:
|
|
styles(std::ostream& a_out):m_out(a_out){}
|
|
virtual ~styles(){}
|
|
public:
|
|
styles(const styles& a_from)
|
|
:m_out(a_from.m_out)
|
|
,m_named_styles(a_from.m_named_styles)
|
|
,m_aliases(a_from.m_aliases)
|
|
,m_cmaps(a_from.m_cmaps)
|
|
{}
|
|
styles& operator=(const styles& a_from){
|
|
m_named_styles = a_from.m_named_styles;
|
|
m_aliases = a_from.m_aliases;
|
|
m_cmaps = a_from.m_cmaps;
|
|
return *this;
|
|
}
|
|
public:
|
|
std::ostream& out() const {return m_out;}
|
|
|
|
const sg::cmaps_t& cmaps() const {return m_cmaps;}
|
|
sg::cmaps_t& cmaps() {return m_cmaps;}
|
|
|
|
typedef std::pair<std::string,std::string> style_item_t;
|
|
typedef std::vector<style_item_t> style_t;
|
|
typedef std::pair<std::string,style_t> named_style_t;
|
|
|
|
const std::vector<named_style_t>& named_styles() const {return m_named_styles;}
|
|
std::vector<named_style_t>& named_styles() {return m_named_styles;}
|
|
|
|
typedef std::pair<std::string,std::string> alias_t;
|
|
const std::vector<alias_t>& aliases() const {return m_aliases;}
|
|
std::vector<alias_t>& aliases() {return m_aliases;}
|
|
|
|
const style_t* find_style(const std::string& a_name) const {
|
|
tools_vforcit(named_style_t,m_named_styles,it){
|
|
if((*it).first==a_name) return &((*it).second);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
style_t* find_style(const std::string& a_name) {
|
|
tools_vforit(named_style_t,m_named_styles,it){
|
|
if((*it).first==a_name) return &((*it).second);
|
|
}
|
|
return 0;
|
|
}
|
|
void remove_item_in_style(style_t& a_style,const std::string& a_item) {
|
|
remove<std::string,std::string>(a_style,a_item);
|
|
}
|
|
*/
|
|
|
|
void find_styles(const std::string& a_pattern,std::vector<std::string>& a_v) const {
|
|
a_v.clear();
|
|
tools_vforcit(named_style_t,m_named_styles,it){
|
|
if(match((*it).first,a_pattern)) a_v.push_back((*it).first);
|
|
}
|
|
}
|
|
|
|
void add_style(const std::string& a_name,const style_t& a_style) {
|
|
tools_vforit(named_style_t,m_named_styles,it){
|
|
if((*it).first==a_name) { //override
|
|
//::printf("debug : styles::add_style : override : \"%s\"\n",a_name.c_str());
|
|
(*it).second = a_style;
|
|
return;
|
|
}
|
|
}
|
|
//::printf("debug : styles::add_style : push_back \"%s\"\n",a_name.c_str());
|
|
m_named_styles.push_back(named_style_t(a_name,a_style));
|
|
}
|
|
|
|
void remove_styles(const std::string& a_pattern) {
|
|
std::vector<named_style_t>::iterator it;
|
|
for(it=m_named_styles.begin();it!=m_named_styles.end();) {
|
|
if(match((*it).first,a_pattern)) {
|
|
it = m_named_styles.erase(it);
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void append(const styles& a_from) {
|
|
//::printf("debug : styles::append ...\n");
|
|
tools_vforcit(named_style_t,a_from.m_named_styles,it) {
|
|
//::printf("debug : styles::append \"%s\"\n",(*it).first.c_str());
|
|
m_named_styles.push_back(*it);
|
|
}
|
|
}
|
|
|
|
bool is_alias(const std::string& a_wanted,std::string& a_style) const {
|
|
if(find(m_aliases,a_wanted,a_style)) return true;
|
|
a_style = a_wanted;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
bool res_string(const std::string& a_style,
|
|
const std::string& a_key,
|
|
std::string& a_v) const {
|
|
std::map<std::string,style_t>::const_iterator it = m_styles.find(a_style);
|
|
if(it==m_styles.end()) {a_v.clear();return false;}
|
|
const style_t& sty = (*it).second;
|
|
if(!find(sty,a_key,a_v)) {a_v.clear();return false;}
|
|
return true;
|
|
}
|
|
*/
|
|
template <class T>
|
|
bool res_value(const style_t& a_sty,const std::string& a_key,T& a_v,const std::string& a_msg) const {
|
|
//NOTE : if ret false, we do not set a_v to something.
|
|
|
|
std::string _s;
|
|
if(!find(a_sty,a_key,_s)) {
|
|
if(a_msg.size()) {
|
|
m_out << "tools::xml::styles::res_value :"
|
|
<< " key " << sout(a_key) << " not found"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< std::endl;
|
|
}
|
|
return false;
|
|
}
|
|
T v;
|
|
if(!to(_s,v)) {
|
|
m_out << "tools::xml::styles::res_value :"
|
|
<< " for key " << sout(a_key) << " not found"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< " can't convert " << sout(_s) << " to value."
|
|
<< std::endl;
|
|
return false;
|
|
}
|
|
a_v = v;
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
bool res_value(const std::string& a_style,const std::string& a_key,T& a_v) const {
|
|
//NOTE : if ret false, we do not set a_v to something.
|
|
|
|
//look if a_style is an alias :
|
|
std::string style;
|
|
is_alias(a_style,style);
|
|
|
|
const style_t* sty = find_style(style);
|
|
if(!sty) {
|
|
//m_out << "tools::xml::styles::res_value :"
|
|
// << " style " << sout(style) << " not found."
|
|
// << std::endl;
|
|
return false;
|
|
}
|
|
T v;
|
|
if(!res_value<T>(*sty,a_key,v,style)) return false;
|
|
a_v = v;
|
|
return true;
|
|
}
|
|
|
|
bool res_color(const style_t& a_sty,const std::string& a_key,colorf& a_color,const std::string& a_msg) const {
|
|
//NOTE : if ret false, we do not set a_color to something.
|
|
std::string s;
|
|
if(!find(a_sty,a_key,s)) {
|
|
if(a_msg.size()) {
|
|
m_out << "tools::xml::styles::res_color :"
|
|
<< " key " << sout(a_key) << " not found"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< std::endl;
|
|
}
|
|
return false;
|
|
}
|
|
if(!sg::find_color(m_cmaps,s,a_color)) {
|
|
m_out << "tools::xml::styles::res_color :"
|
|
<< " key " << sout(a_key) << " is not a color"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< std::endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool res_color(const std::string& a_style,const std::string& a_key,colorf& a_color) const {
|
|
//NOTE : if ret false, we do not set a_color to something.
|
|
|
|
//look if a_style is an alias :
|
|
std::string style;
|
|
is_alias(a_style,style);
|
|
|
|
const style_t* sty = find_style(style);
|
|
if(!sty) {
|
|
//m_out << "tools::xml::styles::res_color :"
|
|
// << " style " << sout(style) << " not found."
|
|
// << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return res_color(*sty,a_key,a_color,style);
|
|
}
|
|
|
|
bool res_bool(const style_t& a_sty,const std::string& a_key,bool& a_v,const std::string& a_msg) const {
|
|
//NOTE : if ret false, we do not set a_v to something.
|
|
std::string s;
|
|
if(!find(a_sty,a_key,s)) {
|
|
if(a_msg.size()) {
|
|
m_out << "tools::xml::styles::res_bool :"
|
|
<< " key " << sout(a_key) << " not found"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< std::endl;
|
|
}
|
|
return false;
|
|
}
|
|
bool v;
|
|
if(!to(s,v)) {
|
|
m_out << "tools::xml::styles::res_bool :"
|
|
<< " for key " << sout(a_key) << " not found"
|
|
<< " in style " << sout(a_msg) << "."
|
|
<< " can't convert " << sout(s) << " to bool."
|
|
<< std::endl;
|
|
return false;
|
|
}
|
|
a_v = v;
|
|
return true;
|
|
}
|
|
|
|
bool res_bool(const std::string& a_style,const std::string& a_key,bool& a_v) const {
|
|
//NOTE : if ret false, we do not set a_color to something.
|
|
|
|
//look if a_style is an alias :
|
|
std::string style;
|
|
is_alias(a_style,style);
|
|
|
|
const style_t* sty = find_style(style);
|
|
if(!sty) {
|
|
//m_out << "tools::xml::styles::res_color :"
|
|
// << " style " << sout(style) << " not found."
|
|
// << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return res_bool(*sty,a_key,a_v,style);
|
|
}
|
|
|
|
// for plotter :
|
|
template <class T> //T = [style,text_style,line_style]
|
|
bool res_sg_style(const std::string& a_style,T& a_sg_style) const {
|
|
//NOTE : a_sg_style is changed according to what is found.
|
|
// Then it is not fully reset by this method.
|
|
const style_t* sty = find_style(a_style);
|
|
if(!sty) {
|
|
//could be ok to not find a plotter sub style.
|
|
//m_out << "tools::sg::gui_viewer::res_sg_style :"
|
|
// << " style " << sout(a_style) << " not found."
|
|
// << std::endl;
|
|
return false;
|
|
}
|
|
|
|
std::string _s;
|
|
tools_vforcit(style_item_t,*sty,vit) {
|
|
if(vit!=(*sty).begin()) _s += "\n";
|
|
_s += (*vit).first;
|
|
_s += " ";
|
|
_s += (*vit).second;
|
|
}
|
|
return a_sg_style.from_string(m_out,m_cmaps,_s);
|
|
}
|
|
|
|
typedef sg::style_colormap cmap_t;
|
|
bool find_colormap(const std::string& a_name,cmap_t& a_cmap) const {
|
|
std::map<std::string,cmap_t>::const_iterator it = m_cmaps.find(a_name);
|
|
if(it==m_cmaps.end()) return false;
|
|
a_cmap = (*it).second;
|
|
return true;
|
|
}
|
|
void add_colormap(const std::string& a_name,const cmap_t& a_cmap) {
|
|
m_cmaps[a_name] = a_cmap;
|
|
}
|
|
//void clear_colormaps() {m_cmaps.clear();/*add default*/}
|
|
|
|
public:
|
|
static bool is_plotter_style(const style_t& a_sty) {
|
|
tools_vforcit(style_item_t,a_sty,it) {
|
|
const std::string& key = (*it).first;
|
|
const std::string& sv = (*it).second;
|
|
if((key=="tag")&&(sv=="plotter_style")) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
void find_plotter_styles(std::vector<std::string>& a_v) const {
|
|
a_v.clear();
|
|
tools_vforcit(named_style_t,m_named_styles,it) {
|
|
if(is_plotter_style((*it).second)) a_v.push_back((*it).first);
|
|
}
|
|
}
|
|
|
|
void dump() {
|
|
tools_vforcit(named_style_t,m_named_styles,it) {
|
|
|
|
m_out << "/////////////////////////////////////" << std::endl;
|
|
m_out << "/// " << (*it).first << std::endl;
|
|
m_out << "/////////////////////////////////////" << std::endl;
|
|
|
|
const style_t& sty = (*it).second;
|
|
|
|
tools_vforcit(style_item_t,sty,vit) {
|
|
m_out << " " << (*vit).first << " " << (*vit).second << std::endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
bool print_plotter_style(std::ostream& a_out,const std::string& a_style) {
|
|
std::string _beg = a_style+".";
|
|
bool found = false;
|
|
tools_vforcit(named_style_t,m_named_styles,it) {
|
|
const std::string& _name = (*it).first;
|
|
if((_name==a_style)||is_beg(_name,_beg)) {
|
|
found = true;
|
|
a_out << (*it).first << " :" << std::endl;
|
|
const style_t& sty = (*it).second;
|
|
tools_vforcit(style_item_t,sty,vit) {
|
|
if((*vit).first=="tag") continue;
|
|
a_out << " " << (*vit).first << " " << (*vit).second << std::endl;
|
|
}
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
void list_plotter_styles(std::ostream& a_out) {
|
|
tools_vforcit(named_style_t,m_named_styles,it) {
|
|
const style_t& sty = (*it).second;
|
|
if(!styles::is_plotter_style(sty)) continue;
|
|
a_out << (*it).first << std::endl;
|
|
}
|
|
}
|
|
protected:
|
|
std::ostream& m_out;
|
|
//styles :
|
|
std::vector<named_style_t> m_named_styles;
|
|
std::vector<alias_t> m_aliases;
|
|
//cmaps :
|
|
sg::cmaps_t m_cmaps;
|
|
};
|
|
|
|
}}
|
|
|
|
#include "tree"
|
|
#include "../vmanip"
|
|
|
|
namespace tools {
|
|
namespace xml {
|
|
|
|
inline void load_style(styles& a_styles,const tree& a_tree) {
|
|
std::string name;
|
|
a_tree.attribute_value("name",name);
|
|
if(name.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_style :"
|
|
<< " <style> without name."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
styles::style_t sty;
|
|
|
|
{looper _for(a_tree);
|
|
while(element* _elem = _for.next_element()) {
|
|
|
|
if(_elem->name()=="copy") {
|
|
|
|
std::string from;
|
|
_elem->attribute_value("from",from); //expect another style name.
|
|
if(from.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_style :"
|
|
<< " <copy> without from."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
const styles::style_t* csty = a_styles.find_style(from);
|
|
if(!csty) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_style :"
|
|
<< " <copy> : from " << sout(from) << " not found."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
append(sty,*csty);
|
|
|
|
} else {
|
|
sty.push_back(styles::style_item_t(_elem->name(),_elem->value()));
|
|
}
|
|
|
|
}}
|
|
|
|
if(sty.size()) a_styles.add_style(name,sty);
|
|
}
|
|
|
|
inline void load_plotter_style(styles& a_styles,const tree& a_tree) {
|
|
std::string pname;
|
|
a_tree.attribute_value("name",pname);
|
|
if(pname.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style :"
|
|
<< " <plotter_style> without name."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
{styles::style_t sty;
|
|
sty.push_back(styles::style_item_t("tag","plotter_style"));
|
|
|
|
{looper _for(a_tree);
|
|
while(element* _elem = _for.next_element()) {
|
|
|
|
if(_elem->name()=="copy") {
|
|
|
|
std::string from;
|
|
_elem->attribute_value("from",from); //expect a plotter_style name.
|
|
if(from.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style :"
|
|
<< " <copy> without from."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
const styles::style_t* csty = a_styles.find_style(from);
|
|
if(!csty) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style :"
|
|
<< " <copy> : from " << sout(from) << " not found."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
if(csty->size()) a_styles.add_style(pname,*csty);
|
|
|
|
if(styles::is_plotter_style(*csty)) {
|
|
//search all <from>.<sub_style> styles :
|
|
std::string head = from+".";
|
|
std::string::size_type l = head.size();
|
|
|
|
styles sts(a_styles.out());
|
|
|
|
const std::vector<styles::named_style_t>& nss = a_styles.named_styles();
|
|
tools_vforcit(styles::named_style_t,nss,it){
|
|
const std::string& name = (*it).first;
|
|
if(name.substr(0,l)==head) {
|
|
std::string tail = name.substr(l,name.size()-l);
|
|
const styles::style_t& ssty = (*it).second;
|
|
if(ssty.size()) sts.add_style(pname+"."+tail,ssty);
|
|
}
|
|
}
|
|
|
|
a_styles.append(sts);
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
sty.push_back(styles::style_item_t(_elem->name(),_elem->value()));
|
|
}
|
|
|
|
}}
|
|
|
|
if(sty.size()) a_styles.add_style(pname,sty);}
|
|
|
|
{looper _for(a_tree);
|
|
while(tree* _tree = _for.next_tree()) {
|
|
|
|
const std::string& tag = _tree->tag_name();
|
|
if(tag=="style") {
|
|
|
|
std::string name;
|
|
_tree->attribute_value("name",name);
|
|
if(name.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style :"
|
|
<< " <style> without name."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
{styles::style_t sty;
|
|
|
|
{looper _for2(*_tree);
|
|
while(element* _elem = _for2.next_element()) {
|
|
if(_elem->name()=="copy") {
|
|
std::string from;
|
|
_elem->attribute_value("from",from); //expect another style name.
|
|
if(from.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style : (2) :"
|
|
<< " <copy> without from."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
const styles::style_t* csty = a_styles.find_style(from);
|
|
if(!csty) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style : (2) :"
|
|
<< " <copy> : from " << sout(from) << " not found."
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
append(sty,*csty);
|
|
} else {
|
|
sty.push_back(styles::style_item_t(_elem->name(),_elem->value()));
|
|
}
|
|
}}
|
|
|
|
if(sty.size()) {
|
|
std::string path = pname+"."+name;
|
|
a_styles.add_style(path,sty);
|
|
}}
|
|
|
|
} else {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_plotter_style :"
|
|
<< " unexpected tag " << sout(tag) << "."
|
|
<< std::endl;
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
inline bool scan_style_tree(styles& a_styles,const tree& a_tree) {
|
|
|
|
if(a_tree.tag_name()!="styles") return false;
|
|
|
|
// look for aliases :
|
|
{looper _for(a_tree);
|
|
while(element* _elem = _for.next_element()) {
|
|
|
|
std::string name;
|
|
_elem->attribute_value("name",name);
|
|
if(name.empty()) {
|
|
a_styles.out() << "tools::sg::gui_viewer::load_style :"
|
|
<< " <alias> without name."
|
|
<< std::endl;
|
|
continue;
|
|
}
|
|
add<std::string,std::string>(a_styles.aliases(),name,_elem->value());
|
|
}}
|
|
|
|
// scan children :
|
|
{looper _for(a_tree);
|
|
while(tree* _tree = _for.next_tree()) {
|
|
|
|
const std::string& tag = _tree->tag_name();
|
|
if(tag=="style") {
|
|
load_style(a_styles,*_tree);
|
|
} else if(tag=="plotter_style") {
|
|
load_plotter_style(a_styles,*_tree);
|
|
}
|
|
|
|
}}
|
|
|
|
return true;
|
|
}
|
|
}}
|
|
|
|
#endif
|