#include <algorithm>
#include <typeinfo>
#include <sstream>
#include "legendbox.h"
#include "graph_drawer.h"
#include "frame.h"
#include "exc.H"
namespace blop
{
length legendbox::default_borderwidth_(new length::base_id_t(terminal::LW));
void legendbox::default_borderwidth(const length &l) { default_borderwidth_ = l; }
bool legendbox::default_multi_ = false;
void legendbox::default_multi(bool f) { default_multi_ = f; }
color legendbox::default_bordercolor_(0,0,0);
void legendbox::default_bordercolor(const color &c) { default_bordercolor_ = c; }
color legendbox::default_fillcolor_(1,1,1);
void legendbox::default_fillcolor(const color &c) { default_fillcolor_ = c; }
bool legendbox::default_draw_border_ = true;
void legendbox::default_draw_border(bool f) { default_draw_border_ = f; }
bool legendbox::default_fill_ = true;
void legendbox::default_fill(bool f) { default_fill_ = f; }
length legendbox::default_bordersep_(new length::base_id_t(terminal::MM));
void legendbox::default_bordersep(const length &l) { default_bordersep_ = l; }
length legendbox::default_legend_sample_sep_ = lincombi(2,terminal::MM);
void legendbox::default_legend_sample_sep(const length &l) { default_legend_sample_sep_ = l; }
length legendbox::default_sample_sample_sep_(new length::base_id_t(terminal::MM));
void legendbox::default_sample_sample_sep(const length &l) { default_sample_sample_sep_ = l; }
length legendbox::default_sample_length_ = lincombi(4,terminal::MM);
void legendbox::default_samplen( const length &l ) { default_sample_length_ = l; }
length legendbox::default_row_sep_(new length::base_id_t(terminal::EX));
void legendbox::default_row_sep(const length &l) { default_row_sep_ = l; }
legendbox &legendbox::mknew(container &parent)
{
legendbox *l = new legendbox;
l->autodel(true);
parent.add(l);
return *l;
}
void legendbox::print(terminal *term)
{
if(print_me_ < 2) return;
if(entries_.empty()) return;
{
bool something = false;
for(unsigned int i=0; i<entries_.size(); ++i)
{
if(!skip_(entries_[i])) something = true;
}
if(!something) return;
}
term->open_layer(layer_);
{
vector<terminal::coord> cc;
if(draw_border_ || fill_)
{
cc.push_back(terminal::coord(left().termspecific_id(),
bottom().termspecific_id()));
cc.push_back(terminal::coord(right().termspecific_id(),
bottom().termspecific_id()));
cc.push_back(terminal::coord(right().termspecific_id(),
top().termspecific_id()));
cc.push_back(terminal::coord(left().termspecific_id(),
top().termspecific_id()));
cc.push_back(terminal::coord(left().termspecific_id(),
bottom().termspecific_id()));
}
if(fill_)
{
term->set_color(fillcolor_);
term->fill_polygon(cc);
}
if(draw_border_)
{
term->set_linewidth(borderwidth_.termspecific_id());
term->set_linestyle(sym::solid);
term->set_color(bordercolor_);
term->draw_lines(cc);
}
}
for(unsigned int i=0; i<entries_.size(); ++i)
{
if(skip_(entries_[i])) continue;
if(entries_[i]->multi_number == 1) entries_[i]->legend.print(term);
if(entries_[i]->multi_number >= 1 && entries_[i]->gr)
{
graph_drawer *d = entries_[i]->gr->drawstyle();
d->draw_sample(entries_[i]->sample_x,
entries_[i]->sample_y,
sample_length_,
entries_[i]->gr,
term);
}
}
term->close_layer(layer_);
}
void legendbox::prepare_for_draw()
{
if(print_me_ < 1) return;
left().register_me();
right().register_me();
bottom().register_me();
top().register_me();
sample_length_.register_me();
if(draw_border_) borderwidth_.register_me();
for(unsigned int i=0; i<entries_.size(); ++i)
{
if(skip_(entries_[i])) continue;
entries_[i]->legend.prepare_for_draw();
if(entries_[i]->gr)
{
entries_[i]->sample_x.register_me();
entries_[i]->sample_y.register_me();
}
}
}
legendbox &legendbox::multi(bool i)
{
multi_ = i;
return *this;
}
void legendbox::add_line()
{
entry *e = new entry;
e->line = true;
e->gr = 0;
e->multi_number = 1;
entries_.push_back(e);
}
label &legendbox::add(const var &t)
{
entry *e = new entry;
e->line = false;
e->gr = 0;
e->legend.text(t);
e->multi_number = 1;
entries_.push_back(e);
return e->legend;
}
void legendbox::add(blop::plottable *g)
{
entry *e = new entry;
e->line = false;
e->gr = g;
e->multi_number = 1;
entries_.push_back(e);
}
bool legendbox::remove(blop::plottable *g)
{
for(unsigned int i=0; i<entries_.size(); ++i)
{
if(entries_[i]->gr == g)
{
delete entries_[i];
entries_.erase(entries_.begin() + i);
return true;
}
}
return false;
}
void legendbox::clear()
{
for(unsigned int i=0; i<entries_.size(); ++i)
{
delete entries_[i];
}
entries_.clear();
}
bool legendbox::skip_(legendbox::entry *e)
{
if(e->gr == 0) return false;
plottable *g = e->gr;
graph_drawer *d = g->drawstyle();
if(d == 0 || !d->draws_sample()) return true;
if(g->legend().str() == "") return true;
return false;
}
void legendbox::update()
{
vector<var> different_labels;
vector<legendbox::entry*> entries;
for(unsigned int i=0; i<entries_.size(); ++i)
{
if(!skip_(entries_[i])) entries.push_back(entries_[i]);
}
max_multisample_ = 1;
for(unsigned int i=0; i<entries.size(); ++i)
{
int prev = -1;
if(multi_ && entries[i]->gr)
{
for(unsigned int j=0; j<i; ++j)
{
if(entries[j]->gr == 0) continue;
if(entries[i]->gr->legend().str() ==
entries[j]->gr->legend().str())
{
if(prev < 0) prev = j;
plottable *g1 = entries[i]->gr;
plottable *g2 = entries[j]->gr;
string p1, p2, l1, l2;
{
ostringstream ost;
ost<<g1->pointsize();
p1 = ost.str();
}
{
ostringstream ost;
ost<<g2->pointsize();
p2 = ost.str();
}
{
ostringstream ost;
ost<<g1->linewidth();
l1 = ost.str();
}
{
ostringstream ost;
ost<<g2->linewidth();
l2 = ost.str();
}
if(typeid(*(g1->drawstyle())) == typeid(*(g2->drawstyle())) &&
g1->fillcolor() == g2->fillcolor() &&
g1->fill() == g2->fill() &&
g1->linecolor() == g2->linecolor() &&
g1->linestyle() == g2->linestyle() &&
equals(g1->pointtype(), g2->pointtype()) &&
g1->pointcolor() == g2->pointcolor() &&
p1 == p2 &&
l1 == l2)
{
entries[i]->multi_number = 0;
}
else entries[i]->multi_number = entries[j]->multi_number+1;
}
}
}
if(entries[i]->multi_number > max_multisample_)
max_multisample_ = entries[i]->multi_number;
if(entries[i]->gr)
{
entries[i]->legend.text(entries[i]->gr->legend());
entries[i]->legend.textcolor(entries[i]->gr->legendcolor());
entries[i]->sample_y = !entries[i]->legend.bottom() + 0.5 * !entries[i]->legend.height();
entries[i]->sample_x = !legend_xpos_ + !legend_sample_sep_ +
(entries[i]->multi_number - 1) * !sample_sample_sep_ +
(entries[i]->multi_number - 1 + 0.5) * !sample_length_;
}
if(prev < 0)
{
if(entries[i]->gr) different_labels.push_back(entries[i]->gr->legend());
else different_labels.push_back(entries[i]->legend.text());
entries[i]->legend.x(!legend_xpos_,sym::right);
if(i == 0)
{
if(draw_border_) entries[i]->legend.y(!top() - !bordersep_,sym::top);
else entries[i]->legend.y(!top(),sym::top);
}
else
{
entries[i]->legend.y(!entries[i-1]->legend.bottom() - !row_sep_, sym::top);
}
}
else
{
entries[i]->legend = entries[prev]->legend;
}
}
if(different_labels.empty()) return;
max_legendwidth_ = maxwidth(different_labels);
if(draw_border_)
{
legend_xpos_ = !left() + !bordersep_ + !max_legendwidth_;
calculated_width_ =
!max_legendwidth_ +
2*!bordersep_ +
!legend_sample_sep_ +
max_multisample_*!sample_length_ +
(max_multisample_ - 1) * !sample_sample_sep_;
calculated_height_ = 2*!bordersep_ + (different_labels.size() - 1) * !row_sep_;
}
else
{
legend_xpos_ = !left() + !max_legendwidth_;
calculated_width_ =
!max_legendwidth_ +
!legend_sample_sep_ +
max_multisample_*!sample_length_ +
(max_multisample_ - 1) * !sample_sample_sep_;
calculated_height_ = (different_labels.size() - 1) * !row_sep_;
}
for(unsigned int i=0; i<entries.size(); ++i)
{
if(entries[i]->multi_number == 1)
calculated_height_ += entries[i]->legend.height();
}
}
legendbox &legendbox::width(length len)
{
if(!len.initialized()) box::width(!calculated_width_);
else box::width(len);
return *this;
}
legendbox &legendbox::left(const length &l)
{
box::left(l);
return *this;
}
legendbox &legendbox::right(const length &l)
{
box::right(l);
return *this;
}
legendbox &legendbox::xcenter(const length &l)
{
box::xcenter(l);
return *this;
}
legendbox &legendbox::bottom(const length &l)
{
box::bottom(l);
return *this;
}
legendbox &legendbox::top(const length &l)
{
box::top(l);
return *this;
}
legendbox &legendbox::ycenter(const length &l)
{
box::ycenter(l);
return *this;
}
legendbox &legendbox::height(length len)
{
if(!len.initialized()) box::height(!calculated_height_);
else box::height(len);
return *this;
}
legendbox &legendbox::borderwidth(const length &l)
{
borderwidth_ = l;
return *this;
}
const length &legendbox::borderwidth() const
{
return borderwidth_;
}
legendbox::~legendbox()
{
std::vector<blop::legendbox*>::iterator i = find(all().begin(), all().end(), this);
if(i == all().end())
err("Unregistered legendbox (programming error)");
all().erase(i);
}
legendbox::legendbox()
: multi_(default_multi_), max_multisample_(0)
{
name("legendbox");
layer("legend");
all().push_back(this);
box::width(!calculated_width_);
box::height(!calculated_height_);
bordercolor_ = default_bordercolor_;
fillcolor_ = default_fillcolor_;
draw_border_ = default_draw_border_;
fill_ = default_fill_;
borderwidth_ = default_borderwidth_;
legend_xpos_ = !left() + !bordersep_ + !max_legendwidth_;
bordersep_ = default_bordersep_;
legend_sample_sep_ = default_legend_sample_sep_;
sample_sample_sep_ = default_sample_sample_sep_;
sample_length_ = default_sample_length_;
row_sep_ = default_row_sep_;
}
legendbox &legendbox::bordercolor(const color &c)
{
bordercolor_ = c;
draw_border_ = true;
return *this;
}
const color &legendbox::bordercolor() const
{
return bordercolor_;
}
legendbox &legendbox::fillcolor(const color &c)
{
fillcolor_ = c;
fill_ = true;
return *this;
}
const color &legendbox::fillcolor() const
{
return fillcolor_;
}
legendbox &legendbox::draw_border(bool i)
{
draw_border_ = i;
return *this;
}
bool legendbox::draw_border() const
{
return draw_border_;
}
legendbox &legendbox::fill(bool i)
{
fill_ = i;
return *this;
}
bool legendbox::fill() const
{
return fill_;
}
legendbox &legendbox::samplen(const length &l)
{
sample_length_ = l;
return *this;
}
const length &legendbox::samplen() const
{
return sample_length_;
}
legendbox &legendbox::bordersep(const length &l)
{
bordersep_ = l;
return *this;
}
const length &legendbox::bordersep() const
{
return bordersep_;
}
legendbox &legendbox::legend_sample_sep(const length &l)
{
legend_sample_sep_ = l;
return *this;
}
const length &legendbox::legend_sample_sep() const
{
return legend_sample_sep_;
}
legendbox &legendbox::sample_sample_sep(const length &l)
{
sample_sample_sep_ = l;
return *this;
}
const length &legendbox::sample_sample_sep() const
{
return sample_sample_sep_;
}
legendbox &legendbox::row_sep(const length &l)
{
row_sep_ = l;
return *this;
}
const length &legendbox::row_sep() const
{
return row_sep_;
}
std::vector<blop::legendbox*> &legendbox::all()
{
static vector<legendbox*> *f = new vector<legendbox*>;
return *f;
}
void legendbox::remove_from_all(plottable *p)
{
for(unsigned int i=0; i<all().size(); ++i)
{
all()[i]->remove(p);
}
}
}