Ejemplo n.º 1
0
CImagePtr
CSVGFeImage::
filterImage(CImagePtr src_image)
{
  if (! src_image.isValid()) return CImagePtr();

  CImagePtr dst_image = src_image->dup();

  CSVGFilter *filter = NULL;

  CSVGObject *parent = parent_;

  while (parent != NULL) {
    filter = dynamic_cast<CSVGFilter *>(parent);

    if (filter != NULL) break;
  }

  if (filter) {
    CBBox2D bbox;

    filter->getObject()->getBBox(bbox);

    if (bbox.isSet())
      dst_image->reshape(bbox.getWidth(), bbox.getHeight());
  }

  return dst_image;
}
void
CQIllustratorCreateTextToolbar::
setSize(const CBBox2D &bbox)
{
  double w = bbox.getWidth();
  double h = bbox.getHeight();

  widthEdit_ ->setValue(w);
  heightEdit_->setValue(h);
}
Ejemplo n.º 3
0
void
CSVGBuffer::
beginDraw(int w, int h, const CBBox2D &bbox)
{
  renderer_->setSize(w, h);

  renderer_->beginDraw();

  renderer_->setDataRange(bbox.getXMin(), bbox.getYMin(), bbox.getXMax(), bbox.getYMax());
}
Ejemplo n.º 4
0
QRectF
CQIllustratorShape::
getQRect() const
{
  CBBox2D bbox = getBBox();

  if (bbox.isSet())
    return CQUtil::toQRect(bbox);
  else
    return QRectF();
}
Ejemplo n.º 5
0
void
CQIllustratorShape::
setBBox(const CBBox2D &bbox)
{
  checkoutShape(CQIllustratorData::ChangeType::GEOMETRY);

  moveTo(bbox.getLL());

  resizeTo(bbox.getWidth(), bbox.getHeight());

  checkinShape(CQIllustratorData::ChangeType::GEOMETRY);
}
Ejemplo n.º 6
0
void
CSVGBuffer::
setup(const CBBox2D &bbox)
{
  reset();

  CSVGRenderer *renderer = getRenderer();

  double x1 = bbox.getXMin();
  double y1 = bbox.getYMin();
  double x2 = bbox.getXMax();
  double y2 = bbox.getYMax();

  renderer->setSize(x2 - x1, y2 - y1);

  renderer->setDataRange(x1, y2, x2, x1);
}
Ejemplo n.º 7
0
// get bbox transformed to top
CBBox2D
CQIllustratorShape::
getFlatBBox() const
{
  CBBox2D bbox = getBBox();

  if (! bbox.isSet())
    return bbox;

  if (! parent_)
    return bbox;

  // if parent transform pby parent flat matric
  const CMatrix2D &m = parent_->getFlatMatrix();

  CPoint2D p1 = m*bbox.getLL();
  CPoint2D p2 = m*bbox.getLR();
  CPoint2D p3 = m*bbox.getUL();
  CPoint2D p4 = m*bbox.getUR();

  CBBox2D bbox1(p1, p2);

  bbox1 += p3;
  bbox1 += p4;

  return bbox1;
}
Ejemplo n.º 8
0
void
CSVGBuffer::
pathText(const string &text, CFontPtr font, CHAlignType align)
{
  renderer_->setFont(font);

  CBBox2D box;

  renderer_->textBounds(text, box);

  int dx;

  if      (align == CHALIGN_TYPE_LEFT)
    dx = 0;
  else if (align == CHALIGN_TYPE_CENTER)
    dx = -box.getWidth()/2;
  else if (align == CHALIGN_TYPE_RIGHT)
    dx = -box.getWidth();

  renderer_->pathRMoveTo(CPoint2D(dx, 0));

  renderer_->pathText(text);
}
Ejemplo n.º 9
0
void
CQIllustratorShape::
drawSelect(CQIllustratorShapeDrawer *drawer)
{
  CBBox2D bbox = getFlatBBox();

  if (bbox.isSet()) {
    CPoint2D p1 = bbox.getLL();
    CPoint2D p2 = bbox.getLR();
    CPoint2D p3 = bbox.getUR();
    CPoint2D p4 = bbox.getUL();

    drawer->drawControlLine(p1, p2);
    drawer->drawControlLine(p2, p3);
    drawer->drawControlLine(p3, p4);
    drawer->drawControlLine(p4, p1);
  }
}
void
CQIllustratorAlignMode::
align(CQIllustrator::AlignSide side, bool commit)
{
  CQIllustratorSelectedShapes *selection = illustrator_->getSelection();

  if (selection->empty()) return;

  //------

  if (illustrator_->getFlipY()) {
    if      (side == CQIllustrator::ALIGN_BOTTOM) side = CQIllustrator::ALIGN_TOP;
    else if (side == CQIllustrator::ALIGN_TOP   ) side = CQIllustrator::ALIGN_BOTTOM;
  }

  //------

  CQIllustratorShape *ashape = 0;

  CBBox2D abbox;
  CBBox2D bbbox;
  bool    afixed = false;

  CQIllustratorAlignToolbar::AnchorMode anchorMode = toolbar_->getAnchorMode();

  if      (anchorMode == CQIllustratorAlignToolbar::AnchorMode::SELECTION) {
    // get anchor shape for side

    CQIllustratorSelectedShapes::iterator ps1, ps2;

    ps1 = selection->begin();
    ps2 = selection->end();

    for ( ; ps1 != ps2; ++ps1) {
      CQIllustratorShape *shape = (*ps1).getShape();

      bbbox += shape->getFlatBBox();
    }

    ps1 = selection->begin();

    for ( ; ps1 != ps2; ++ps1) {
      CQIllustratorShape *shape = (*ps1).getShape();

      const CBBox2D &bbox = shape->getFlatBBox();

      if (! abbox.isSet() || (! afixed && shape->getFixed())) {
        ashape = shape;
        abbox  = bbox;
        afixed = ashape->getFixed();

        continue;
      }

      if (afixed && ! shape->getFixed())
        continue;

      if ((side == CQIllustrator::ALIGN_LEFT       && bbox.getXMin() < abbox.getXMin()) ||
          (side == CQIllustrator::ALIGN_BOTTOM     && bbox.getYMin() < abbox.getYMin()) ||
          (side == CQIllustrator::ALIGN_RIGHT      && bbox.getXMax() > abbox.getXMax()) ||
          (side == CQIllustrator::ALIGN_TOP        && bbox.getYMax() > abbox.getYMax()) ||
          (side == CQIllustrator::ALIGN_HORIZONTAL && bbox.getYMid() < abbox.getYMid()) ||
          (side == CQIllustrator::ALIGN_VERTICAL   && bbox.getXMid() < abbox.getXMid())) {
        ashape = shape;
        abbox  = bbox;
        afixed = ashape->getFixed();
      }
    }
  }
  else if (anchorMode == CQIllustratorAlignToolbar::AnchorMode::OBJECT) {
    CQIllustratorShape *shape = illustrator_->getShape(toolbar_->getAnchorObject().toStdString());

    if (shape == 0) return;

    CQIllustratorAlignToolbar::ObjectEdgeType edgeType =
      toolbar_->getAnchorObjectEdgeType();

    abbox = shape->getFlatBBox();

    if      (edgeType == CQIllustratorAlignToolbar::ObjectEdgeType::LEFT_BOTTOM)
      abbox = CBBox2D(abbox.getLL(), abbox.getLR());
    else if (edgeType == CQIllustratorAlignToolbar::ObjectEdgeType::RIGHT_TOP)
      abbox = CBBox2D(abbox.getUR(), abbox.getUR());
    else if (edgeType == CQIllustratorAlignToolbar::ObjectEdgeType::MIDDLE)
      abbox = CBBox2D(abbox.getCenter(), abbox.getCenter());

    bbbox = abbox;
  }
  else if (anchorMode == CQIllustratorAlignToolbar::AnchorMode::POSITION) {
    QPointF pos = toolbar_->getAnchorPosition();

    abbox = CBBox2D(CQUtil::fromQPoint(pos), CQUtil::fromQPoint(pos));

    CQIllustratorSelectedShapes::iterator ps1 = selection->begin(), ps2 = selection->end();

    for ( ; ps1 != ps2; ++ps1) {
      CQIllustratorShape *shape = (*ps1).getShape();

      const CBBox2D &bbox = shape->getFlatBBox();

      bbbox += bbox;
    }
  }
  else
    return;

  // align

  double offset = toolbar_->getOffset();

  if (commit) {
    illustrator_->startUndoGroup("Align");

    CQIllustratorSelectedShapes::iterator ps1 = selection->begin(), ps2 = selection->end();

    for ( ; ps1 != ps2; ++ps1) {
      CQIllustratorShape *shape = (*ps1).getShape();

      if (shape->getFixed()) continue;

      const CBBox2D &bbox = shape->getFlatBBox();

      double dx = 0.0, dy = 0.0;

      if (shape != ashape) {
        if      (side == CQIllustrator::ALIGN_LEFT      ) dx = abbox.getXMin() - bbox.getXMin();
        else if (side == CQIllustrator::ALIGN_BOTTOM    ) dy = abbox.getYMin() - bbox.getYMin();
        else if (side == CQIllustrator::ALIGN_RIGHT     ) dx = abbox.getXMax() - bbox.getXMax();
        else if (side == CQIllustrator::ALIGN_TOP       ) dy = abbox.getYMax() - bbox.getYMax();
        else if (side == CQIllustrator::ALIGN_HORIZONTAL) dy = abbox.getYMid() - bbox.getYMid();
        else if (side == CQIllustrator::ALIGN_VERTICAL  ) dx = abbox.getXMid() - bbox.getXMid();
      }

      if      (side == CQIllustrator::ALIGN_LEFT      ) dx += offset;
      else if (side == CQIllustrator::ALIGN_BOTTOM    ) dy += offset;
      else if (side == CQIllustrator::ALIGN_RIGHT     ) dx -= offset;
      else if (side == CQIllustrator::ALIGN_TOP       ) dy -= offset;
      else if (side == CQIllustrator::ALIGN_HORIZONTAL) dy += offset;
      else if (side == CQIllustrator::ALIGN_VERTICAL  ) dx += offset;

      shape->moveBy(CPoint2D(dx, dy));
    }

    illustrator_->endUndoGroup();

    illustrator_->setDimmed(false);

    illustrator_->clearPreviewObjects();

    illustrator_->redraw();
  }
  else {
    illustrator_->clearPreviewObjects();

    CQIllustratorSelectedShapes::iterator ps1 = selection->begin(), ps2 = selection->end();

    for ( ; ps1 != ps2; ++ps1) {
      CQIllustratorShape *shape = (*ps1).getShape();

      if (shape->getFixed()) continue;

      const CBBox2D &bbox = shape->getFlatBBox();

      double dx = 0.0, dy = 0.0;

      if (shape != ashape) {
        if      (side == CQIllustrator::ALIGN_LEFT      ) dx = abbox.getXMin() - bbox.getXMin();
        else if (side == CQIllustrator::ALIGN_BOTTOM    ) dy = abbox.getYMin() - bbox.getYMin();
        else if (side == CQIllustrator::ALIGN_RIGHT     ) dx = abbox.getXMax() - bbox.getXMax();
        else if (side == CQIllustrator::ALIGN_TOP       ) dy = abbox.getYMax() - bbox.getYMax();
        else if (side == CQIllustrator::ALIGN_HORIZONTAL) dy = abbox.getYMid() - bbox.getYMid();
        else if (side == CQIllustrator::ALIGN_VERTICAL  ) dx = abbox.getXMid() - bbox.getXMid();
      }

      if      (side == CQIllustrator::ALIGN_LEFT      ) dx += offset;
      else if (side == CQIllustrator::ALIGN_BOTTOM    ) dy += offset;
      else if (side == CQIllustrator::ALIGN_RIGHT     ) dx -= offset;
      else if (side == CQIllustrator::ALIGN_TOP       ) dy -= offset;
      else if (side == CQIllustrator::ALIGN_HORIZONTAL) dy += offset;
      else if (side == CQIllustrator::ALIGN_VERTICAL  ) dx += offset;

      illustrator_->addPreviewObject(new CQIllustrator::PreviewShape(shape, CPoint2D(dx, dy)));
    }

    double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;

    if      (side == CQIllustrator::ALIGN_LEFT || side == CQIllustrator::ALIGN_RIGHT) {
      x1 = abbox.getXMin();
      x2 = abbox.getXMax();

      y1 = bbbox.getYMin();
      y2 = bbbox.getYMax();
    }
    else if (side == CQIllustrator::ALIGN_BOTTOM || side == CQIllustrator::ALIGN_TOP) {
      y1 = abbox.getYMin();
      y2 = abbox.getYMax();

      x1 = bbbox.getXMin();
      x2 = bbbox.getXMax();
    }
    else if (side == CQIllustrator::ALIGN_HORIZONTAL) {
      x1 = bbbox.getXMin();
      x2 = bbbox.getXMax();

      y1 = abbox.getYMid();
      y2 = y2;
    }
    else if (side == CQIllustrator::ALIGN_VERTICAL) {
      y1 = bbbox.getYMin();
      y2 = bbbox.getYMax();

      x1 = abbox.getXMid();
      x2 = x1;
    }

    double dx = (x2 - x1)/8;
    double dy = (y2 - y1)/8;

    if      (side == CQIllustrator::ALIGN_LEFT      )
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x1, y1 - dy), CPoint2D(x1, y2 + dy)));
    else if (side == CQIllustrator::ALIGN_BOTTOM    )
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x1 - dx, y1), CPoint2D(x2 + dx, y1)));
    else if (side == CQIllustrator::ALIGN_RIGHT     )
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x2, y1 - dy), CPoint2D(x2, y2 + dy)));
    else if (side == CQIllustrator::ALIGN_TOP       )
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x1 - dx, y2), CPoint2D(x2 + dx, y2)));
    else if (side == CQIllustrator::ALIGN_HORIZONTAL)
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x1 - dx, y1), CPoint2D(x2 + dx, y1)));
    else if (side == CQIllustrator::ALIGN_VERTICAL  )
      illustrator_->addPreviewObject(
        new CQIllustrator::PreviewLine(CPoint2D(x1, y1 - dy), CPoint2D(x1, y2 + dy)));

    illustrator_->redrawOverlay();
  }
}
Ejemplo n.º 11
0
void
CGnuPlotStyleBoxErrorBars::
draw2D(CGnuPlotPlot *plot, CGnuPlotRenderer *renderer)
{
  CGnuPlotBoxErrorBarsStyleValue *value =
    CGnuPlotStyleValueMgrInst->getValue<CGnuPlotBoxErrorBarsStyleValue>(plot);

  if (! value) {
    value = plot->app()->device()->createBoxErrorBarsStyleValue(plot);

    value->init();

    CGnuPlotStyleValueMgrInst->setValue<CGnuPlotBoxErrorBarsStyleValue>(plot, value);
  }

  //---

  const CGnuPlotLineStyle &lineStyle = plot->lineStyle();

  CGnuPlotFill   fill  (plot);
  CGnuPlotStroke stroke(plot);

  bool isCalcColor = lineStyle.isCalcColor();

  CBBox2D bbox = plot->bbox2D();

  double ymin = bbox.getYMin();

  double y2 = std::max(0.0, ymin);

  double bw = value->getSpacing();

  //---

  if (! renderer->isPseudo())
    plot->updateBoxBarCacheSize(plot->getPoints2D().size());

  //---

  int i = 0;

  for (const auto &point : plot->getPoints2D()) {
    std::vector<double> reals;

    (void) point.getReals(reals);

    COptReal colorVal;

    if (isCalcColor && ! reals.empty()) {
      colorVal = reals.back();

      reals.pop_back();
    }

    while (reals.size() < 3)
      reals.push_back(0.0);

    double x  = reals[0];
    double y  = reals[1];
    double dx = bw;
    double dy = 0.0;
    double yl = y;
    double yh = y;

    // x y ydelta
    if      (reals.size() == 3) {
      dy = reals[2];

      yl = y - dy;
      yh = y + dy;
    }
    else if (reals.size() == 4) {
      // x y ydelta xdelta
      if (! value->isAutoWidth()) {
        dx = reals[2];
        dy = reals[3];

        yl = y - dy;
        yh = y + dy;
      }
      // x y ylow yhigh
      else {
        yl = reals[2];
        yh = reals[3];
      }
    }
    // x y ylow yhigh xdelta
    else if (reals.size() >= 5) {
      yl = reals[2];
      yh = reals[3];
      dx = reals[4];
    }

    //---

    COptRGBA lc;

    if (colorVal.isValid()) {
      if (renderer->isPseudo())
        renderer->setCBValue(colorVal.getValue());
      else
        lc = lineStyle.calcColor(plot, colorVal.getValue());
    }

    //---

    CBBox2D bbox(x - dx/2, y2, x + dx/2, y);

    CPoint2D p1(x, yl);
    CPoint2D p2(x, yh);

    if (! renderer->isPseudo()) {
      CGnuPlotBoxBarObject *bar = plot->boxBarObjects()[i];

      bar->setBBox(bbox);

      bar->setValues(x, y);

      bar->setVertical(true);

      if (! bar->testAndSetUsed()) {
        CGnuPlotFillP   fill  (bar->fill  ()->dup());
        CGnuPlotStrokeP stroke(bar->stroke()->dup());

        bar->setFill  (fill  );
        bar->setStroke(stroke);

        //---

        bar->clearEndBars();

        CGnuPlotEndBarP endBar = bar->addEndBar(p1, p2);

        endBar->setStartLine(true);
        endBar->setEndLine  (true);
        endBar->setEndWidth (dx/2);

        CGnuPlotStrokeP endStroke(bar->stroke()->dup());

        endBar->setStroke(endStroke);
      }
    }
    else {
      CGnuPlotStroke stroke;

      stroke.setEnabled(true);

      renderer->strokeRect(bbox, stroke);

      renderer->strokeClipLine(p1, p2, stroke);

      double w = dx/2;

      renderer->strokeClipLine(p1 - CPoint2D(w/2, 0), p1 + CPoint2D(w/2, 0), stroke);
      renderer->strokeClipLine(p2 - CPoint2D(w/2, 0), p2 + CPoint2D(w/2, 0), stroke);
    }

    ++i;
  }

  if (! renderer->isPseudo()) {
    for (const auto &bar : plot->boxBarObjects())
      bar->draw(renderer);
  }
}
Ejemplo n.º 12
0
void
CSVGBuffer::
drawImage(const CBBox2D &bbox, CImagePtr image)
{
  renderer_->drawImage(bbox.getLL(), image);
}
Ejemplo n.º 13
0
void
CGnuPlotStyleRadar::
drawKey(CGnuPlotPlot *plot, CGnuPlotRenderer *renderer)
{
  CGnuPlotRadarStyleValue *value =
    CGnuPlotStyleValueMgrInst->getValue<CGnuPlotRadarStyleValue>(plot);
  if (! value) return;

  //---

  CGnuPlotGroup *group = plot->group();

  const CGnuPlotKeyP     &key   = group->key();
  const CGnuPlotAxisData &xaxis = group->xaxis(1);

  if (! key->isDisplayed()) return;

  if (key->getFont().isValid())
    renderer->setFont(key->getFont());

  CGnuPlotFill fill(plot);

  //---

  CBBox2D rbbox = (key->isOutside() ? group->getRegionBBox() : renderer->range());

  //---

  CFontPtr font = renderer->getFont();

  double font_size = font->getCharAscent() + font->getCharDescent();

  double pw = renderer->pixelWidthToWindowWidth  (1);
  double ph = renderer->pixelHeightToWindowHeight(1);

  double bx = 8*pw;
  double by = 8*ph;
  double bw = font_size - 2;

  CSize2D size;

  double textWidth = 0.0, textHeight = 0.0;

  std::string header;

  if (key->hasTitle()) {
    header = key->title();

    if (header != "")
      textHeight += font_size*ph;
  }

  int i = 0;

  for (const auto &point : plot->getPoints2D()) {
    assert(! point.isDiscontinuity());

    std::string label = xaxis.iticLabel(i);
    //std::string label = point.label();

    textWidth = std::max(textWidth, font->getStringWidth(label)*pw);

    textHeight += font_size*ph;

    ++i;
  }

  size = CSize2D(textWidth + bw*pw + 3*bx, textHeight + 2*by);

  CHAlignType halign = key->getHAlign();
  CVAlignType valign = key->getVAlign();

  double x1 = 0, y1 = 0;

  if      (halign == CHALIGN_TYPE_LEFT)
    x1 = rbbox.getLeft () + bx;
  else if (halign == CHALIGN_TYPE_RIGHT)
    x1 = rbbox.getRight() - bx - size.getWidth();
  else if (halign == CHALIGN_TYPE_CENTER)
    x1 = rbbox.getXMid() - size.getWidth()/2;

  if      (valign == CVALIGN_TYPE_TOP)
    y1 = rbbox.getTop   () - by - size.getHeight();
  else if (valign == CVALIGN_TYPE_BOTTOM)
    y1 = rbbox.getBottom() + by;
  else if (valign == CVALIGN_TYPE_CENTER)
    y1 = rbbox.getYMid() - size.getHeight()/2;

  double x2 = x1 + size.getWidth ();
  double y2 = y1 + size.getHeight();

  CBBox2D bbox(x1, y1, x2, y2);

  if (key->getFillBox()) {
    renderer->fillRect(bbox, fill.background());
  }

  if (key->getDrawBox()) {
    CRGBA c(0, 0, 0);

    if (key->hasLineType())
      c = CGnuPlotStyleInst->indexColor(value->palette(), key->getLineType());

    renderer->drawRect(bbox, c, 1);
  }

  double y = y2 - by;

  if (header != "") {
    CRGBA tc = CRGBA(0,0,0);

    renderer->drawHAlignedText(CPoint2D((x1 + x2)/2, y), HAlignPos(CHALIGN_TYPE_CENTER, 0),
                               VAlignPos(CVALIGN_TYPE_TOP, 0), header, tc);

    y -= font_size*ph;
  }

  int pi = 0;

  for (const auto &point : plot->getPoints2D()) {
    assert(! point.isDiscontinuity());

    double xx = (key->isReverse() ? x1 + bx : x2 - bw*pw - bx);
    double yy = y - font_size*ph/2;

    CPoint2D p1(xx, yy - bw*ph/2), p2(xx + bw*pw, yy + bw*ph/2);

    CRGBA lc, fc;

    getPointsColor(value, pi + 1, lc, fc);

    CBBox2D bbox(p1, p2);

    renderer->fillRect(bbox, fc);
    renderer->drawRect(bbox, lc, 1);

    std::string label = xaxis.iticLabel(pi);
    //std::string label = point.label();

    //double lw = font->getStringWidth(label);

    CRGBA tc = CRGBA(0,0,0);

    if (key->isReverse())
      renderer->drawHAlignedText(CPoint2D(xx + bw*pw + bx, y), HAlignPos(CHALIGN_TYPE_LEFT, 0),
                                 VAlignPos(CVALIGN_TYPE_TOP, 0), label, tc);
    else
      renderer->drawHAlignedText(CPoint2D(xx - bx, y), HAlignPos(CHALIGN_TYPE_RIGHT, 0),
                                 VAlignPos(CVALIGN_TYPE_TOP, 0), label, tc);

    y -= font_size*ph;

    ++pi;
  }
}
Ejemplo n.º 14
0
void
CGnuPlotStylePieChart::
drawKey(CGnuPlotPlot *plot, CGnuPlotRenderer *renderer)
{
  CGnuPlotPieChartStyleValue *value =
    CGnuPlotStyleValueMgrInst->getValue<CGnuPlotPieChartStyleValue>(plot);
  if (! value) return;

  //---

  CGnuPlotGroup *group = plot->group();

  const CGnuPlotKeyP     &key   = group->key();
//const CGnuPlotAxisData &xaxis = group->xaxis(1);

  if (! key->isDisplayed()) return;

  if (key->getFont().isValid())
    renderer->setFont(key->getFont());

  CGnuPlotFill fill(plot);

  //---

  CBBox2D rbbox = (key->isOutside() ? group->getRegionBBox() : renderer->range());

  //---

  CFontPtr font = renderer->getFont();

  double font_size = font->getCharAscent() + font->getCharDescent();

  double pw = renderer->pixelWidthToWindowWidth  (1);
  double ph = renderer->pixelHeightToWindowHeight(1);

  double bx = 8*pw;
  double by = 8*ph;
  double bw = font_size - 2;

  CSize2D size;

  double textWidth = 0.0, textHeight = 0.0;

  std::string header;

  if (key->hasTitle()) {
    header = key->title();

    if (header != "")
      textHeight += font_size*ph;
  }

  NameValueColors values = nameValueColors(plot, value->palette(), value->alpha());

  for (const auto &v : values) {
    std::string label = v.first;

    textWidth = std::max(textWidth, font->getStringWidth(label)*pw);

    textHeight += font_size*ph;
  }

  size = CSize2D(textWidth + bw*pw + 3*bx, textHeight + 2*by);

  CHAlignType halign = key->getHAlign();
  CVAlignType valign = key->getVAlign();

  double x1 = 0, y1 = 0;

  if      (halign == CHALIGN_TYPE_LEFT)
    x1 = rbbox.getLeft () + bx;
  else if (halign == CHALIGN_TYPE_RIGHT)
    x1 = rbbox.getRight() - bx - size.getWidth();
  else if (halign == CHALIGN_TYPE_CENTER)
    x1 = rbbox.getXMid() - size.getWidth()/2;

  if      (valign == CVALIGN_TYPE_TOP)
    y1 = rbbox.getTop   () - by - size.getHeight();
  else if (valign == CVALIGN_TYPE_BOTTOM)
    y1 = rbbox.getBottom() + by;
  else if (valign == CVALIGN_TYPE_CENTER)
    y1 = rbbox.getYMid() - size.getHeight()/2;

  double x2 = x1 + size.getWidth ();
  double y2 = y1 + size.getHeight();

  CBBox2D bbox(x1, y1, x2, y2);

  if (key->getFillBox()) {
    renderer->fillRect(bbox, fill.background());
  }

  if (key->getDrawBox()) {
    CRGBA c(0, 0, 0);

    if (key->hasLineType())
      c = CGnuPlotStyleInst->indexColor(key->getLineType());

    renderer->drawRect(bbox, c, 1);
  }

  double y = y2 - by;

  if (header != "") {
    renderer->drawHAlignedText(CPoint2D((x1 + x2)/2, y), HAlignPos(CHALIGN_TYPE_CENTER, 0),
                               VAlignPos(CVALIGN_TYPE_TOP, 0), header, CRGBA(0,0,0));

    y -= font_size*ph;
  }

  if (! renderer->isPseudo())
    plot->updatePieCacheSize(values.size());

  int pi = 0;

  for (const auto &v : values) {
    CGnuPlotPieObject *pieObject = 0;

    if (! renderer->isPseudo())
      pieObject = plot->pieObjects()[pi];

    //---

    const std::string   &name = v .first;
    const ValueColor    &vc   = v .second;
    const LineFillColor &lfc  = vc.second;

    double xx = (key->isReverse() ? x1 + bx : x2 - bw*pw - bx);
    double yy = y - font_size*ph/2;

    CPoint2D p1(xx, yy - bw*ph/2), p2(xx + bw*pw, yy + bw*ph/2);

    CBBox2D bbox(p1, p2);

    renderer->fillEllipse(bbox, lfc.second);
    renderer->drawEllipse(bbox, lfc.first, 1);

    //double lw = font->getStringWidth(name);

    CRGBA tc = CRGBA(0,0,0);

    if (key->isReverse())
      renderer->drawHAlignedText(CPoint2D(xx + bw*pw + bx, y), HAlignPos(CHALIGN_TYPE_LEFT, 0),
                                 VAlignPos(CVALIGN_TYPE_TOP, 0), name, tc);
    else
      renderer->drawHAlignedText(CPoint2D(xx - bx, y), HAlignPos(CHALIGN_TYPE_RIGHT, 0),
                                 VAlignPos(CVALIGN_TYPE_TOP, 0), name, tc);

    if (pieObject) {
      CBBox2D keyRect(x1, y - font_size*ph, x2, y);

      pieObject->setKeyRect(keyRect);

      //renderer->drawRect(keyRect, lfc.second, 1);
    }

    y -= font_size*ph;

    ++pi;
  }
}