<commit_before>#include "glyph_layout.hpp"
#include "font_desc.hpp"
#include "resource.hpp"

#include "../base/logging.hpp"
#include "../base/math.hpp"
#include "../std/sstream.hpp"

#include "../geometry/angles.hpp"
#include "../geometry/any_rect2d.hpp"
#include "../base/thread.hpp"

namespace graphics
{
  double GlyphLayout::getKerning(GlyphLayoutElem const & prevElem,
                                 GlyphMetrics const & prevMetrics,
                                 GlyphLayoutElem const & curElem,
                                 GlyphMetrics const & curMetrics)
  {
    double res = 0;
    /// check, whether we should offset this symbol slightly
    /// not to overlap the previous symbol

    m2::AnyRectD prevSymRectAA(
          prevElem.m_pt.Move(prevMetrics.m_height,
                            -prevElem.m_angle.cos(),
                             prevElem.m_angle.sin()), //< moving by angle = prevElem.m_angle - math::pi / 2
          prevElem.m_angle,
          m2::RectD(prevMetrics.m_xOffset,
                    prevMetrics.m_yOffset,
                    prevMetrics.m_xOffset + prevMetrics.m_width,
                    prevMetrics.m_yOffset + prevMetrics.m_height));

    m2::AnyRectD curSymRectAA(
          curElem.m_pt.Move(curMetrics.m_height,
                           -curElem.m_angle.cos(),
                            curElem.m_angle.sin()), //< moving by angle = curElem.m_angle - math::pi / 2
          curElem.m_angle,
          m2::RectD(curMetrics.m_xOffset,
                    curMetrics.m_yOffset,
                    curMetrics.m_xOffset + curMetrics.m_width,
                    curMetrics.m_yOffset + curMetrics.m_height)
          );

    if (prevElem.m_angle.val() == curElem.m_angle.val())
      return res;

    //m2::RectD prevLocalRect = prevSymRectAA.GetLocalRect();
    m2::PointD pts[4];
    prevSymRectAA.GetGlobalPoints(pts);
    curSymRectAA.ConvertTo(pts, 4);

    m2::RectD prevRectInCurSym(pts[0].x, pts[0].y, pts[0].x, pts[0].y);
    prevRectInCurSym.Add(pts[1]);
    prevRectInCurSym.Add(pts[2]);
    prevRectInCurSym.Add(pts[3]);

    m2::RectD const & curSymRect = curSymRectAA.GetLocalRect();

    if (curSymRect.minX() < prevRectInCurSym.maxX())
      res = prevRectInCurSym.maxX() - curSymRect.minX();

    return res;
  }

  GlyphLayout::GlyphLayout()
  {}

  GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
                           FontDesc const & fontDesc,
                           m2::PointD const & pt,
                           strings::UniString const & visText,
                           graphics::EPosition pos)
    : m_firstVisible(0),
      m_lastVisible(visText.size()),
      m_fontDesc(fontDesc),
      m_pivot(pt),
      m_offset(0, 0)
  {
    size_t cnt = visText.size();

    m_entries.resize(cnt);
    m_metrics.resize(cnt);

    if (!m_fontDesc.IsValid())
      return;

    m2::RectD boundRect;
    m2::PointD curPt(0, 0);

    bool isFirst = true;

    for (size_t i = 0; i < visText.size(); ++i)
    {
      GlyphKey glyphKey(visText[i],
                        fontDesc.m_size,
                        //fontDesc.m_isMasked,
                        false, //< calculating glyph positions using unmasked glyphs.
                        fontDesc.m_color);

      GlyphMetrics const m = glyphCache->getGlyphMetrics(glyphKey);

      if (isFirst)
      {
        boundRect = m2::RectD(m.m_xOffset,
                             -m.m_yOffset,
                              m.m_xOffset,
                             -m.m_yOffset);
        isFirst = false;
      }
      else
        boundRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y));

      boundRect.Add(m2::PointD(m.m_xOffset + m.m_width,
                             -(m.m_yOffset + m.m_height)) + curPt);

      GlyphLayoutElem elem;
      elem.m_sym = visText[i];
      elem.m_angle = 0;
      elem.m_pt = curPt;
      m_entries[i] = elem;
      m_metrics[i] = m;

      curPt += m2::PointD(m.m_xAdvance, m.m_yAdvance);
    }

    boundRect.Inflate(2, 2);

    m2::PointD ptOffs(-boundRect.SizeX() / 2 - boundRect.minX(),
                      -boundRect.SizeY() / 2 - boundRect.minY());

    /// adjusting according to position
    if (pos & EPosLeft)
      ptOffs += m2::PointD(-boundRect.SizeX() / 2, 0);

    if (pos & EPosRight)
      ptOffs += m2::PointD(boundRect.SizeX() / 2, 0);

    if (pos & EPosAbove)
      ptOffs += m2::PointD(0, -boundRect.SizeY() / 2);

    if (pos & EPosUnder)
      ptOffs += m2::PointD(0, boundRect.SizeY() / 2);

    for (unsigned i = 0; i < m_entries.size(); ++i)
      m_entries[i].m_pt += ptOffs;

    boundRect.Offset(ptOffs);

    m_boundRects.push_back(m2::AnyRectD(boundRect));
  }

  GlyphLayout::GlyphLayout(GlyphLayout const & src,
                           math::Matrix<double, 3, 3> const & m)
    : m_firstVisible(0),
      m_lastVisible(0),
      m_path(src.m_path, m),
      m_visText(src.m_visText),
      m_pos(src.m_pos),
      m_fontDesc(src.m_fontDesc),
      m_metrics(src.m_metrics),
      m_pivot(0, 0),
      m_offset(0, 0)
  {
    if (!m_fontDesc.IsValid())
      return;
    m_boundRects.push_back(m2::AnyRectD(m2::RectD(0, 0, 0, 0)));
    recalcAlongPath();
  }

  GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
                           FontDesc const & fontDesc,
                           m2::PointD const * pts,
                           size_t ptsCount,
                           strings::UniString const & visText,
                           double fullLength,
                           double pathOffset,
                           graphics::EPosition pos)
    : m_firstVisible(0),
      m_lastVisible(0),
      m_path(pts, ptsCount, fullLength, pathOffset),
      m_visText(visText),
      m_pos(pos),
      m_fontDesc(fontDesc),
      m_pivot(0, 0),
      m_offset(0, 0)
  {
    if (!m_fontDesc.IsValid())
      return;
    m_boundRects.push_back(m2::AnyRectD(m2::RectD(0, 0, 0, 0)));

    size_t cnt = m_visText.size();

    m_metrics.resize(cnt);

    for (size_t i = 0; i < cnt; ++i)
    {
      GlyphKey key(visText[i],
                   m_fontDesc.m_size,
                   //m_fontDesc.m_isMasked,
                   false, //< calculating glyph positions using the unmasked glyphs.
                   graphics::Color(0, 0, 0, 0));
      m_metrics[i] = glyphCache->getGlyphMetrics(key);
    }
    recalcAlongPath();
  }

  void GlyphLayout::recalcAlongPath()
  {
    // get vector of glyphs and calculate string length
    double strLength = 0.0;
    size_t count = m_visText.size();

    if (count != 0)
      m_entries.resize(count);

    for (size_t i = 0; i < m_entries.size(); ++i)
    {
      m_entries[i].m_sym = m_visText[i];
      strLength += m_metrics[i].m_xAdvance;
    }

    if (m_path.fullLength() < strLength)
      return;

    PathPoint arrPathStart = m_path.front();

    m_pivot = m_path.offsetPoint(arrPathStart, m_path.fullLength() / 2.0).m_pt;

    // offset of the text from path's start
    double offset = (m_path.fullLength() - strLength) / 2.0;

    if (m_pos & graphics::EPosLeft)
    {
      offset = 0;
      m_pivot = arrPathStart.m_pt;
    }

    if (m_pos & graphics::EPosRight)
    {
      offset = (m_path.fullLength() - strLength);
      m_pivot = m_path.get(m_path.size() - 1);
    }

    // calculate base line offset
    double blOffset = 2 - m_fontDesc.m_size / 2;
    // on-path kerning should be done for baseline-centered glyphs
    //double kernOffset = blOffset;

    if (m_pos & graphics::EPosUnder)
      blOffset = 2 - m_fontDesc.m_size;
    if (m_pos & graphics::EPosAbove)
      blOffset = 2;

    offset -= m_path.pathOffset();
    if (-offset >= strLength)
      return;

    // find first visible glyph
    size_t symPos = 0;
    while (offset < 0 &&  symPos < count)
      offset += m_metrics[symPos++].m_xAdvance;

    PathPoint glyphStartPt = m_path.offsetPoint(arrPathStart, offset);

    m_firstVisible = symPos;

    GlyphLayoutElem prevElem; //< previous glyph, to compute kerning from
    GlyphMetrics prevMetrics;
    bool hasPrevElem = false;

    for (; symPos < count; ++symPos)
    {
      /// full advance, including possible kerning.
      double fullGlyphAdvance = m_metrics[symPos].m_xAdvance;

      GlyphMetrics const & metrics = m_metrics[symPos];

      if (glyphStartPt.m_i == -1)
        return;

      if (metrics.m_width != 0)
      {
        double fullKern = 0;
        double kern = 0;

        int i = 0;
        for (; i < 100; ++i)
        {
          PivotPoint pivotPt = m_path.findPivotPoint(glyphStartPt, metrics, fullKern);

          if (pivotPt.m_pp.m_i == -1)
            return;

          m_entries[symPos].m_angle = pivotPt.m_angle;
          double centerOffset = metrics.m_xOffset + metrics.m_width / 2.0;
          m_entries[symPos].m_pt = pivotPt.m_pp.m_pt.Move(-centerOffset,
                                                          m_entries[symPos].m_angle.sin(),
                                                          m_entries[symPos].m_angle.cos());

//          m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(blOffset, m_entries[symPos].m_angle - math::pi / 2);
//        sin(a - pi / 2) == -cos(a)
//        cos(a - pi / 2) == sin(a)
          m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(blOffset,
                                                               -m_entries[symPos].m_angle.cos(),
                                                               m_entries[symPos].m_angle.sin());

//          m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(kernOffset, m_entries[symPos].m_angle - math::pi / 2);

          // < check whether we should "kern"
          if (hasPrevElem)
          {
            kern = getKerning(prevElem,
                              prevMetrics,
                              m_entries[symPos],
                              m_metrics[symPos]);
            if (kern < 0.5)
              kern = 0;

            fullGlyphAdvance += kern;
            fullKern += kern;
          }

          if (kern == 0)
            break;
        }
        if (i == 100)
        {
          LOG(LINFO, ("100 iteration on computing kerning exceeded. possibly infinite loop occured"));
        }

        /// kerning should be computed for baseline centered glyph
        prevElem = m_entries[symPos];
        prevMetrics = m_metrics[symPos];
        hasPrevElem = true;

        // < align to baseline
//        m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(blOffset - kernOffset, m_entries[symPos].m_angle - math::pi / 2);
      }
      else
      {
        if (symPos == m_firstVisible)
        {
          m_firstVisible = symPos + 1;
        }
        else
        {
          m_entries[symPos].m_angle = ang::AngleD();
          m_entries[symPos].m_pt = glyphStartPt.m_pt;
        }
      }

      glyphStartPt = m_path.offsetPoint(glyphStartPt, fullGlyphAdvance);
      offset += fullGlyphAdvance;

      m_lastVisible = symPos + 1;
    }

    /// storing glyph coordinates relative to pivot point.
    for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
      m_entries[i].m_pt -= m_pivot;

    computeBoundRects();
  }

  void GlyphLayout::computeBoundRects()
  {
    map<double, m2::AnyRectD> rects;

    for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
    {
      if (m_metrics[i].m_width != 0)
      {
        ang::AngleD const & a = m_entries[i].m_angle;

        map<double, m2::AnyRectD>::iterator it = rects.find(a.val());

        m2::AnyRectD symRectAA(
              m_entries[i].m_pt.Move(m_metrics[i].m_height + m_metrics[i].m_yOffset, -a.cos(), a.sin()), //< moving by angle = m_entries[i].m_angle - math::pi / 2
              a,
              m2::RectD(m_metrics[i].m_xOffset,
                        0,
                        m_metrics[i].m_xOffset + m_metrics[i].m_width,
                        m_metrics[i].m_height
                        ));

        if (it == rects.end())
          rects[a.val()] = symRectAA;
        else
          rects[a.val()].Add(symRectAA);
      }
    }

    m_boundRects.clear();

    for (map<double, m2::AnyRectD>::const_iterator it = rects.begin(); it != rects.end(); ++it)
    {
      m2::AnyRectD r(it->second);
      m2::PointD zero = r.GlobalZero();

      double dx = zero.x - floor(zero.x);
      double dy = zero.y - floor(zero.y);

      r.Offset(m2::PointD(-dx, -dy));

      r.Offset(m_pivot);

      m_boundRects.push_back(r);
    }
  }

  size_t GlyphLayout::firstVisible() const
  {
    return m_firstVisible;
  }

  size_t GlyphLayout::lastVisible() const
  {
    return m_lastVisible;
  }

  buffer_vector<GlyphLayoutElem, 32> const & GlyphLayout::entries() const
  {
    return m_entries;
  }

  buffer_vector<m2::AnyRectD, 16> const & GlyphLayout::boundRects() const
  {
    return m_boundRects;
  }

  m2::PointD const & GlyphLayout::pivot() const
  {
    return m_pivot;
  }

  void GlyphLayout::setPivot(m2::PointD const & pivot)
  {
    for (unsigned i = 0; i < m_boundRects.size(); ++i)
      m_boundRects[i].Offset(pivot - m_pivot);

    m_pivot = pivot;
  }

  m2::PointD const & GlyphLayout::offset() const
  {
    return m_offset;
  }

  void GlyphLayout::setOffset(m2::PointD const & offset)
  {
    for (unsigned i = 0; i < m_boundRects.size(); ++i)
      m_boundRects[i].Offset(offset - m_offset);

    m_offset = offset;
  }

  graphics::FontDesc const & GlyphLayout::fontDesc() const
  {
    return m_fontDesc;
  }
}
<commit_msg>Avoid too bended labels<commit_after>#include "glyph_layout.hpp"
#include "font_desc.hpp"
#include "resource.hpp"

#include "../base/logging.hpp"
#include "../base/math.hpp"
#include "../std/sstream.hpp"

#include "../geometry/angles.hpp"
#include "../geometry/any_rect2d.hpp"
#include "../base/thread.hpp"

namespace graphics
{
  double GlyphLayout::getKerning(GlyphLayoutElem const & prevElem,
                                 GlyphMetrics const & prevMetrics,
                                 GlyphLayoutElem const & curElem,
                                 GlyphMetrics const & curMetrics)
  {
    double res = 0;
    /// check, whether we should offset this symbol slightly
    /// not to overlap the previous symbol

    m2::AnyRectD prevSymRectAA(
          prevElem.m_pt.Move(prevMetrics.m_height,
                            -prevElem.m_angle.cos(),
                             prevElem.m_angle.sin()), //< moving by angle = prevElem.m_angle - math::pi / 2
          prevElem.m_angle,
          m2::RectD(prevMetrics.m_xOffset,
                    prevMetrics.m_yOffset,
                    prevMetrics.m_xOffset + prevMetrics.m_width,
                    prevMetrics.m_yOffset + prevMetrics.m_height));

    m2::AnyRectD curSymRectAA(
          curElem.m_pt.Move(curMetrics.m_height,
                           -curElem.m_angle.cos(),
                            curElem.m_angle.sin()), //< moving by angle = curElem.m_angle - math::pi / 2
          curElem.m_angle,
          m2::RectD(curMetrics.m_xOffset,
                    curMetrics.m_yOffset,
                    curMetrics.m_xOffset + curMetrics.m_width,
                    curMetrics.m_yOffset + curMetrics.m_height)
          );

    if (prevElem.m_angle.val() == curElem.m_angle.val())
      return res;

    //m2::RectD prevLocalRect = prevSymRectAA.GetLocalRect();
    m2::PointD pts[4];
    prevSymRectAA.GetGlobalPoints(pts);
    curSymRectAA.ConvertTo(pts, 4);

    m2::RectD prevRectInCurSym(pts[0].x, pts[0].y, pts[0].x, pts[0].y);
    prevRectInCurSym.Add(pts[1]);
    prevRectInCurSym.Add(pts[2]);
    prevRectInCurSym.Add(pts[3]);

    m2::RectD const & curSymRect = curSymRectAA.GetLocalRect();

    if (curSymRect.minX() < prevRectInCurSym.maxX())
      res = prevRectInCurSym.maxX() - curSymRect.minX();

    return res;
  }

  GlyphLayout::GlyphLayout()
  {}

  GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
                           FontDesc const & fontDesc,
                           m2::PointD const & pt,
                           strings::UniString const & visText,
                           graphics::EPosition pos)
    : m_firstVisible(0),
      m_lastVisible(visText.size()),
      m_fontDesc(fontDesc),
      m_pivot(pt),
      m_offset(0, 0)
  {
    size_t cnt = visText.size();

    m_entries.resize(cnt);
    m_metrics.resize(cnt);

    if (!m_fontDesc.IsValid())
      return;

    m2::RectD boundRect;
    m2::PointD curPt(0, 0);

    bool isFirst = true;

    for (size_t i = 0; i < visText.size(); ++i)
    {
      GlyphKey glyphKey(visText[i],
                        fontDesc.m_size,
                        //fontDesc.m_isMasked,
                        false, //< calculating glyph positions using unmasked glyphs.
                        fontDesc.m_color);

      GlyphMetrics const m = glyphCache->getGlyphMetrics(glyphKey);

      if (isFirst)
      {
        boundRect = m2::RectD(m.m_xOffset,
                             -m.m_yOffset,
                              m.m_xOffset,
                             -m.m_yOffset);
        isFirst = false;
      }
      else
        boundRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y));

      boundRect.Add(m2::PointD(m.m_xOffset + m.m_width,
                             -(m.m_yOffset + m.m_height)) + curPt);

      GlyphLayoutElem elem;
      elem.m_sym = visText[i];
      elem.m_angle = 0;
      elem.m_pt = curPt;
      m_entries[i] = elem;
      m_metrics[i] = m;

      curPt += m2::PointD(m.m_xAdvance, m.m_yAdvance);
    }

    boundRect.Inflate(2, 2);

    m2::PointD ptOffs(-boundRect.SizeX() / 2 - boundRect.minX(),
                      -boundRect.SizeY() / 2 - boundRect.minY());

    /// adjusting according to position
    if (pos & EPosLeft)
      ptOffs += m2::PointD(-boundRect.SizeX() / 2, 0);

    if (pos & EPosRight)
      ptOffs += m2::PointD(boundRect.SizeX() / 2, 0);

    if (pos & EPosAbove)
      ptOffs += m2::PointD(0, -boundRect.SizeY() / 2);

    if (pos & EPosUnder)
      ptOffs += m2::PointD(0, boundRect.SizeY() / 2);

    for (unsigned i = 0; i < m_entries.size(); ++i)
      m_entries[i].m_pt += ptOffs;

    boundRect.Offset(ptOffs);

    m_boundRects.push_back(m2::AnyRectD(boundRect));
  }

  GlyphLayout::GlyphLayout(GlyphLayout const & src,
                           math::Matrix<double, 3, 3> const & m)
    : m_firstVisible(0),
      m_lastVisible(0),
      m_path(src.m_path, m),
      m_visText(src.m_visText),
      m_pos(src.m_pos),
      m_fontDesc(src.m_fontDesc),
      m_metrics(src.m_metrics),
      m_pivot(0, 0),
      m_offset(0, 0)
  {
    if (!m_fontDesc.IsValid())
      return;
    m_boundRects.push_back(m2::AnyRectD(m2::RectD(0, 0, 0, 0)));
    recalcAlongPath();
  }

  GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
                           FontDesc const & fontDesc,
                           m2::PointD const * pts,
                           size_t ptsCount,
                           strings::UniString const & visText,
                           double fullLength,
                           double pathOffset,
                           graphics::EPosition pos)
    : m_firstVisible(0),
      m_lastVisible(0),
      m_path(pts, ptsCount, fullLength, pathOffset),
      m_visText(visText),
      m_pos(pos),
      m_fontDesc(fontDesc),
      m_pivot(0, 0),
      m_offset(0, 0)
  {
    if (!m_fontDesc.IsValid())
      return;
    m_boundRects.push_back(m2::AnyRectD(m2::RectD(0, 0, 0, 0)));

    size_t cnt = m_visText.size();

    m_metrics.resize(cnt);

    for (size_t i = 0; i < cnt; ++i)
    {
      GlyphKey key(visText[i],
                   m_fontDesc.m_size,
                   //m_fontDesc.m_isMasked,
                   false, //< calculating glyph positions using the unmasked glyphs.
                   graphics::Color(0, 0, 0, 0));
      m_metrics[i] = glyphCache->getGlyphMetrics(key);
    }
    recalcAlongPath();
  }

  void GlyphLayout::recalcAlongPath()
  {
    // get vector of glyphs and calculate string length
    double strLength = 0.0;
    size_t count = m_visText.size();

    if (count != 0)
      m_entries.resize(count);

    for (size_t i = 0; i < m_entries.size(); ++i)
    {
      m_entries[i].m_sym = m_visText[i];
      strLength += m_metrics[i].m_xAdvance;
    }

    if (m_path.fullLength() < strLength)
      return;

    PathPoint arrPathStart = m_path.front();

    m_pivot = m_path.offsetPoint(arrPathStart, m_path.fullLength() / 2.0).m_pt;

    // offset of the text from path's start
    double offset = (m_path.fullLength() - strLength) / 2.0;

    if (m_pos & graphics::EPosLeft)
    {
      offset = 0;
      m_pivot = arrPathStart.m_pt;
    }

    if (m_pos & graphics::EPosRight)
    {
      offset = (m_path.fullLength() - strLength);
      m_pivot = m_path.get(m_path.size() - 1);
    }

    // calculate base line offset
    double blOffset = 2 - m_fontDesc.m_size / 2;
    // on-path kerning should be done for baseline-centered glyphs
    //double kernOffset = blOffset;

    if (m_pos & graphics::EPosUnder)
      blOffset = 2 - m_fontDesc.m_size;
    if (m_pos & graphics::EPosAbove)
      blOffset = 2;

    offset -= m_path.pathOffset();
    if (-offset >= strLength)
      return;

    // find first visible glyph
    size_t symPos = 0;
    while (offset < 0 &&  symPos < count)
      offset += m_metrics[symPos++].m_xAdvance;

    PathPoint glyphStartPt = m_path.offsetPoint(arrPathStart, offset);

    m_firstVisible = symPos;

    GlyphLayoutElem prevElem; //< previous glyph, to compute kerning from
    GlyphMetrics prevMetrics;
    bool hasPrevElem = false;

    for (; symPos < count; ++symPos)
    {
      /// full advance, including possible kerning.
      double fullGlyphAdvance = m_metrics[symPos].m_xAdvance;

      GlyphMetrics const & metrics = m_metrics[symPos];

      if (glyphStartPt.m_i == -1)
        return;

      if (metrics.m_width != 0)
      {
        double fullKern = 0;
        double kern = 0;

        bool pathIsTooBended = false;

        int i = 0;
        for (; i < 100; ++i)
        {
          PivotPoint pivotPt = m_path.findPivotPoint(glyphStartPt, metrics, fullKern);

          if (pivotPt.m_pp.m_i == -1)
            return;

          m_entries[symPos].m_angle = pivotPt.m_angle;
          double centerOffset = metrics.m_xOffset + metrics.m_width / 2.0;
          m_entries[symPos].m_pt = pivotPt.m_pp.m_pt.Move(-centerOffset,
                                                          m_entries[symPos].m_angle.sin(),
                                                          m_entries[symPos].m_angle.cos());

          m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(blOffset,
                                                               -m_entries[symPos].m_angle.cos(),
                                                               m_entries[symPos].m_angle.sin());

          // check if angle between letters is too big
          if (hasPrevElem && (ang::GetShortestDistance(prevElem.m_angle.m_val, m_entries[symPos].m_angle.m_val) > 0.8)){
            pathIsTooBended = true;
            break;
          }

          // < check whether we should "kern"
          if (hasPrevElem)
          {
            kern = getKerning(prevElem,
                              prevMetrics,
                              m_entries[symPos],
                              m_metrics[symPos]);
            if (kern < 0.5)
              kern = 0;

            fullGlyphAdvance += kern;
            fullKern += kern;
          }

          if (kern == 0)
            break;
        }
        if (i == 100)
        {
          LOG(LINFO, ("100 iteration on computing kerning exceeded. possibly infinite loop occured"));
        }
        if (pathIsTooBended)
          break;

        /// kerning should be computed for baseline centered glyph
        prevElem = m_entries[symPos];
        prevMetrics = m_metrics[symPos];
        hasPrevElem = true;

        // < align to baseline
//        m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(blOffset - kernOffset, m_entries[symPos].m_angle - math::pi / 2);
      }
      else
      {
        if (symPos == m_firstVisible)
        {
          m_firstVisible = symPos + 1;
        }
        else
        {
          m_entries[symPos].m_angle = ang::AngleD();
          m_entries[symPos].m_pt = glyphStartPt.m_pt;
        }
      }

      glyphStartPt = m_path.offsetPoint(glyphStartPt, fullGlyphAdvance);
      offset += fullGlyphAdvance;

      m_lastVisible = symPos + 1;
    }

    /// storing glyph coordinates relative to pivot point.
    for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
      m_entries[i].m_pt -= m_pivot;

    computeBoundRects();
  }

  void GlyphLayout::computeBoundRects()
  {
    map<double, m2::AnyRectD> rects;

    for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
    {
      if (m_metrics[i].m_width != 0)
      {
        ang::AngleD const & a = m_entries[i].m_angle;

        map<double, m2::AnyRectD>::iterator it = rects.find(a.val());

        m2::AnyRectD symRectAA(
              m_entries[i].m_pt.Move(m_metrics[i].m_height + m_metrics[i].m_yOffset, -a.cos(), a.sin()), //< moving by angle = m_entries[i].m_angle - math::pi / 2
              a,
              m2::RectD(m_metrics[i].m_xOffset,
                        0,
                        m_metrics[i].m_xOffset + m_metrics[i].m_width,
                        m_metrics[i].m_height
                        ));

        if (it == rects.end())
          rects[a.val()] = symRectAA;
        else
          rects[a.val()].Add(symRectAA);
      }
    }

    m_boundRects.clear();

    for (map<double, m2::AnyRectD>::const_iterator it = rects.begin(); it != rects.end(); ++it)
    {
      m2::AnyRectD r(it->second);
      m2::PointD zero = r.GlobalZero();

      double dx = zero.x - floor(zero.x);
      double dy = zero.y - floor(zero.y);

      r.Offset(m2::PointD(-dx, -dy));

      r.Offset(m_pivot);

      m_boundRects.push_back(r);
    }
  }

  size_t GlyphLayout::firstVisible() const
  {
    return m_firstVisible;
  }

  size_t GlyphLayout::lastVisible() const
  {
    return m_lastVisible;
  }

  buffer_vector<GlyphLayoutElem, 32> const & GlyphLayout::entries() const
  {
    return m_entries;
  }

  buffer_vector<m2::AnyRectD, 16> const & GlyphLayout::boundRects() const
  {
    return m_boundRects;
  }

  m2::PointD const & GlyphLayout::pivot() const
  {
    return m_pivot;
  }

  void GlyphLayout::setPivot(m2::PointD const & pivot)
  {
    for (unsigned i = 0; i < m_boundRects.size(); ++i)
      m_boundRects[i].Offset(pivot - m_pivot);

    m_pivot = pivot;
  }

  m2::PointD const & GlyphLayout::offset() const
  {
    return m_offset;
  }

  void GlyphLayout::setOffset(m2::PointD const & offset)
  {
    for (unsigned i = 0; i < m_boundRects.size(); ++i)
      m_boundRects[i].Offset(offset - m_offset);

    m_offset = offset;
  }

  graphics::FontDesc const & GlyphLayout::fontDesc() const
  {
    return m_fontDesc;
  }
}
<|endoftext|>


<commit_before>#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;

template <typename T>
class DataSource_ : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT_T(DataSource_, T, ModelComponent);
    OpenSim_DECLARE_OUTPUT(columns, T, getColumnAtTime, SimTK::Stage::Instance);
// OpenSim_DECLARE_OUTPUT(all, Vector<T>, getRow, SimTK::Stage::Instance);
public:

    T getColumnAtTime(const SimTK::State& s) const {
        return interpolate(s.getTime(), 0);
    }

    T interpolate(const double& time, int rowIndex) const {
        const auto& times(_table.getIndependentColumn());

        // Get the first time greater or equal to the requested time.
        const auto& lowerb = std::lower_bound(times.begin(), times.end(), time);
        const auto& timeLowerb = *lowerb;
        const auto& ilowerb = lowerb - times.begin();
        // If the the time is an exact match to an existing column.
        if (timeLowerb == time) {
            const auto& row = _table.getRowAtIndex(ilowerb);
            return row[rowIndex];
        }

        // Get the latest time that is less than the requested time.
        const auto& below = lowerb - 1;
        const auto& timeBelow = (*below);
        const auto& ibelow = below - times.begin();

        // If we got this far, then lowerb is the first time greater than
        // the requested time.
        const auto& iabove = ilowerb;
        const auto& timeAbove = timeLowerb;

        // Compute fraction within the interval.
        const double numer = time - timeBelow;
        const double denom = timeAbove - timeBelow;
        const double fraction = denom < SimTK::Eps ? 0.0 : numer / denom;

        // Get the rows at the below and above times.
        const auto& rowBelow = _table.getRowAtIndex(ibelow);
        const auto& rowAbove = _table.getRowAtIndex(iabove);

        const T& delta = rowAbove[rowIndex] - rowBelow[rowIndex];
        return rowBelow[rowIndex] + fraction * delta;
    }

    TimeSeriesTable_<T>& updTable() { return _table; }
    const TimeSeriesTable_<T> getTable() const { return _table; }

private:

    TimeSeriesTable_<T> _table;
};

typedef DataSource_<double> DataSource;

template <typename T>
class ConsoleReporter_ : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT_T(ConsoleReporter_, T, Component);
public:
    OpenSim_DECLARE_LIST_INPUT(input, T, SimTK::Stage::Acceleration, "");
private:
    void extendRealizeReport(const State& state) const override {
        const auto& input = getInput("input");

        if (_printCount % 20 == 0) {
            std::cout << "[" << getName() << "] "
                      << std::setw(_width) << "time" << "  ";
            for (auto idx = 0; idx < input.getNumConnectees(); ++idx) {
                const auto& output = Input<T>::downcast(input).getOutput(idx);
                const auto& outName = output.getName();
                const auto& truncName = outName.size() <= _width ?
                    outName : outName.substr(outName.size() - _width);
                std::cout << std::setw(_width) << truncName << "|";
            }
            std::cout << "\n";
        }
        std::cout << "[" << getName() << "] "
                  << std::setw(_width) << state.getTime() << "| ";
        for (auto idx = 0; idx < input.getNumConnectees(); ++idx) {
            const auto& output = Input<T>::downcast(input).getOutput(idx);
            const auto& value = output.getValue(state);
            const auto& nSigFigs = output.getNumberOfSignificantDigits();
            std::cout << std::setw(_width)
                      << std::setprecision(nSigFigs) << value << "|";
        }
        std::cout << std::endl;

        const_cast<ConsoleReporter_<T>*>(this)->_printCount++;
    }
    unsigned int _printCount = 0;
    int _width = 12;
};

typedef ConsoleReporter_<double> ConsoleReporter;

void integrate(const System& system, Integrator& integrator,
        const State& initialState,
        Real finalTime) {
    TimeStepper ts(system, integrator);
    ts.initialize(initialState);
    ts.setReportAllSignificantStates(true);
    integrator.setReturnEveryInternalStep(true);
    while (ts.getState().getTime() < finalTime) {
        ts.stepTo(finalTime);
        system.realize(ts.getState(), SimTK::Stage::Report);
    }
}

void testOutputVectorsAndChannels() {
    Model model;

    // DataSource
    // ----------
    auto* src = new DataSource();
    model.addModelComponent(src);

    // Fill up the DataSource.
    auto& table = src->updTable();

    // Column labels (in only 7 lines!)
    ValueArray<std::string> labelValues;
    auto& vec = labelValues.upd();
    for (unsigned i = 0; i < 5; ++i) {
        vec.push_back(SimTK::Value<std::string>("col" + std::to_string(i)));
    }
    TimeSeriesTable::DependentsMetaData depMeta;
    depMeta.setValueArrayForKey("labels", labelValues);
    table.setDependentsMetaData(depMeta);

    TimeSeriesTable::RowVector row(5, 0.0);
    table.appendRow(0.0, row);
    row += 1;
    table.appendRow(0.25, row);
    row += 1;
    table.appendRow(0.50, row);
    row += 1;
    table.appendRow(0.75, row);
    row += 1;
    table.appendRow(1.0, row);
    row += 1;
    table.appendRow(1.1, row);

    // Reporter
    // --------
    auto* rep = new ConsoleReporter();
    rep->setName("interped");
    model.addModelComponent(rep);

    rep->updInput("input").connect(src->getOutput("columns"));

    SimTK::State& s = model.initSystem();
    RungeKuttaMersonIntegrator integrator(model.getSystem());
    integrator.setFixedStepSize(0.1);
    integrate(model.getSystem(), integrator, s, 1.0);

}

int main() {
    // TODO SimTK_START_TEST("futureOutputVectorsAndChannels");
        SimTK_SUBTEST(testOutputVectorsAndChannels);
    //SimTK_END_TEST();
}

<commit_msg>Start prototyping channels.<commit_after>#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;

template <typename T>
class DataSource_ : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT_T(DataSource_, T, ModelComponent);
    OpenSim_DECLARE_OUTPUT(columns, T, getColumnAtTime, SimTK::Stage::Instance);
// OpenSim_DECLARE_OUTPUT(all, Vector<T>, getRow, SimTK::Stage::Instance);
public:

    T getColumnAtTime(const SimTK::State& s) const {
        return interpolate(s.getTime(), 0);
    }

    T interpolate(const double& time, int rowIndex) const {
        const auto& times(_table.getIndependentColumn());

        // Get the first time greater or equal to the requested time.
        const auto& lowerb = std::lower_bound(times.begin(), times.end(), time);
        const auto& timeLowerb = *lowerb;
        const auto& ilowerb = lowerb - times.begin();
        // If the the time is an exact match to an existing column.
        if (timeLowerb == time) {
            const auto& row = _table.getRowAtIndex(ilowerb);
            return row[rowIndex];
        }

        // Get the latest time that is less than the requested time.
        const auto& below = lowerb - 1;
        const auto& timeBelow = (*below);
        const auto& ibelow = below - times.begin();

        // If we got this far, then lowerb is the first time greater than
        // the requested time.
        const auto& iabove = ilowerb;
        const auto& timeAbove = timeLowerb;

        // Compute fraction within the interval.
        const double numer = time - timeBelow;
        const double denom = timeAbove - timeBelow;
        const double fraction = denom < SimTK::Eps ? 0.0 : numer / denom;

        // Get the rows at the below and above times.
        const auto& rowBelow = _table.getRowAtIndex(ibelow);
        const auto& rowAbove = _table.getRowAtIndex(iabove);

        const T& delta = rowAbove[rowIndex] - rowBelow[rowIndex];
        return rowBelow[rowIndex] + fraction * delta;
    }

    TimeSeriesTable_<T>& updTable() { return _table; }
    const TimeSeriesTable_<T> getTable() const { return _table; }

private:

//    void extendFinalizeFromProperties() const {
//        for (int icol = 0; ++icol < _table.getNumColumns(); ++icol) {
//            getOutput("columns").addChannel()
//        }
//    }

    TimeSeriesTable_<T> _table;
};

typedef DataSource_<double> DataSource;

template <typename T>
class ConsoleReporter_ : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT_T(ConsoleReporter_, T, Component);
public:
    OpenSim_DECLARE_LIST_INPUT(input, T, SimTK::Stage::Acceleration, "");
private:
    void extendRealizeReport(const State& state) const override {
        const auto& input = getInput("input");

        if (_printCount % 20 == 0) {
            std::cout << "[" << getName() << "] "
                      << std::setw(_width) << "time" << "  ";
            for (auto idx = 0; idx < input.getNumConnectees(); ++idx) {
                const auto& output = Input<T>::downcast(input).getOutput(idx);
                const auto& outName = output.getName();
                const auto& truncName = outName.size() <= _width ?
                    outName : outName.substr(outName.size() - _width);
                std::cout << std::setw(_width) << truncName << "|";
            }
            std::cout << "\n";
        }
        std::cout << "[" << getName() << "] "
                  << std::setw(_width) << state.getTime() << "| ";
        for (auto idx = 0; idx < input.getNumConnectees(); ++idx) {
            const auto& output = Input<T>::downcast(input).getOutput(idx);
            const auto& value = output.getValue(state);
            const auto& nSigFigs = output.getNumberOfSignificantDigits();
            std::cout << std::setw(_width)
                      << std::setprecision(nSigFigs) << value << "|";
        }
        std::cout << std::endl;

        const_cast<ConsoleReporter_<T>*>(this)->_printCount++;
    }
    unsigned int _printCount = 0;
    int _width = 12;
};

typedef ConsoleReporter_<double> ConsoleReporter;

void integrate(const System& system, Integrator& integrator,
        const State& initialState,
        Real finalTime) {
    TimeStepper ts(system, integrator);
    ts.initialize(initialState);
    ts.setReportAllSignificantStates(true);
    integrator.setReturnEveryInternalStep(true);
    while (ts.getState().getTime() < finalTime) {
        ts.stepTo(finalTime);
        system.realize(ts.getState(), SimTK::Stage::Report);
    }
}

void testOutputVectorsAndChannels() {
    Model model;

    // DataSource
    // ----------
    auto* src = new DataSource();
    model.addModelComponent(src);

    // Fill up the DataSource.
    auto& table = src->updTable();

    // Column labels (in only 7 lines!)
    ValueArray<std::string> labelValues;
    auto& vec = labelValues.upd();
    for (unsigned i = 0; i < 5; ++i) {
        vec.push_back(SimTK::Value<std::string>("col" + std::to_string(i)));
    }
    TimeSeriesTable::DependentsMetaData depMeta;
    depMeta.setValueArrayForKey("labels", labelValues);
    table.setDependentsMetaData(depMeta);

    TimeSeriesTable::RowVector row(5, 0.0);
    table.appendRow(0.0, row);
    row += 1;
    table.appendRow(0.25, row);
    row += 1;
    table.appendRow(0.50, row);
    row += 1;
    table.appendRow(0.75, row);
    row += 1;
    table.appendRow(1.0, row);
    row += 1;
    table.appendRow(1.1, row);

    // Reporter
    // --------
    auto* rep = new ConsoleReporter();
    rep->setName("interped");
    model.addModelComponent(rep);

    rep->updInput("input").connect(src->getOutput("columns"));

    SimTK::State& s = model.initSystem();
    RungeKuttaMersonIntegrator integrator(model.getSystem());
    integrator.setFixedStepSize(0.1);
    integrate(model.getSystem(), integrator, s, 1.0);

}

int main() {
    // TODO SimTK_START_TEST("futureOutputVectorsAndChannels");
        SimTK_SUBTEST(testOutputVectorsAndChannels);
    //SimTK_END_TEST();
}

<|endoftext|>


<commit_before>AliAnalysisTask *AddTask_ConversionsForNano(
    Int_t dataset = 0, Bool_t isMC = kFALSE, TString periodNameV0Reader = "",
    TString cutnumberPhoton = "00200078400000001240820000") {
  gSystem->Load("libPWGGAGammaConv");

  // get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_V0ReaderV1", "No analysis manager found.");
    return 0;
  }

  // ================== GetInputEventHandler =============================
  AliVEventHandler *inputHandler = mgr->GetInputEventHandler();
  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();

  Bool_t enableV0findingEffi = kFALSE;
  Bool_t fillHistos = kTRUE;
  Bool_t runLightOutput = kTRUE;
  AliConvEventCuts *fEventCuts = NULL;
  AliConversionPhotonCuts *fCuts = NULL;
  TString cutnumberEvent = "00000000";

  AliV0ReaderV1 *fV0ReaderV1 = new AliV0ReaderV1("ConvGammaAODProduction");

  if (periodNameV0Reader.CompareTo("") != 0)
    fV0ReaderV1->SetPeriodName(periodNameV0Reader);
  fV0ReaderV1->SetCreateAODs(kTRUE);
  fV0ReaderV1->SetUseOwnXYZCalculation(kTRUE);
  fV0ReaderV1->SetUseAODConversionPhoton(kTRUE);

  if (!mgr) {
    Error("AddTask_V0ReaderV1", "No analysis manager found.");
    return NULL;
  }

  if (cutnumberEvent != "") {
    fEventCuts =
        new AliConvEventCuts(cutnumberEvent.Data(), cutnumberEvent.Data());
    fEventCuts->SetPreSelectionCutFlag(kTRUE);
    fEventCuts->SetV0ReaderName("ConvGammaAODProduction");
    if (fEventCuts->InitializeCutsFromCutString(cutnumberEvent.Data())) {
      fV0ReaderV1->SetEventCuts(fEventCuts);
    }
  }

  if (cutnumberPhoton != "") {
    fCuts = new AliConversionPhotonCuts(cutnumberPhoton.Data(),
                                        cutnumberPhoton.Data());
    fCuts->SetIsHeavyIon(false);
    fCuts->SetV0ReaderName("ConvGammaAODProduction");
    if (fCuts->InitializeCutsFromCutString(cutnumberPhoton.Data())) {
      fV0ReaderV1->SetConversionCuts(fCuts);
    }
  }
  fV0ReaderV1->Init();
  AliLog::SetGlobalLogLevel(AliLog::kFatal);

  // connect input V0Reader
  mgr->AddTask(fV0ReaderV1);
  mgr->ConnectInput(fV0ReaderV1, 0, cinput);

  AliLog::SetGlobalLogLevel(AliLog::kInfo);

  //================================================
  //              data containers
  //================================================
  //            find input container
  // below the trunk version
  AliAnalysisDataContainer *coutput =
      mgr->CreateContainer("PCM onflyV0Finder container", TBits::Class(),
                           AliAnalysisManager::kExchangeContainer);

  mgr->ConnectOutput(fV0ReaderV1, 1, coutput);

  return fV0ReaderV1;
}
<commit_msg>Improve the photon cuts and enable Addv0InESDFilter<commit_after>AliAnalysisTask *AddTask_ConversionsForNano(
    Int_t dataset = 0, Bool_t isMC = kFALSE, TString periodNameV0Reader = "",
    TString cutnumberPhoton = "00200078000000001240820000") {
  gSystem->Load("libPWGGAGammaConv");

  // get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_V0ReaderV1", "No analysis manager found.");
    return 0;
  }

  // ================== GetInputEventHandler =============================
  AliVEventHandler *inputHandler = mgr->GetInputEventHandler();
  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();

  Bool_t enableV0findingEffi = kFALSE;
  Bool_t fillHistos = kTRUE;
  Bool_t runLightOutput = kTRUE;
  AliConvEventCuts *fEventCuts = NULL;
  AliConversionPhotonCuts *fCuts = NULL;
  TString cutnumberEvent = "00000000";

  AliV0ReaderV1 *fV0ReaderV1 = new AliV0ReaderV1("ConvGammaAODProduction");

  if (periodNameV0Reader.CompareTo("") != 0)
    fV0ReaderV1->SetPeriodName(periodNameV0Reader);
  fV0ReaderV1->SetAddv0sInESDFilter(kTRUE);
  fV0ReaderV1->SetCreateAODs(kTRUE);
  fV0ReaderV1->SetUseOwnXYZCalculation(kTRUE);
  fV0ReaderV1->SetUseAODConversionPhoton(kTRUE);

  if (!mgr) {
    Error("AddTask_V0ReaderV1", "No analysis manager found.");
    return NULL;
  }

  if (cutnumberEvent != "") {
    fEventCuts =
        new AliConvEventCuts(cutnumberEvent.Data(), cutnumberEvent.Data());
    fEventCuts->SetPreSelectionCutFlag(kTRUE);
    fEventCuts->SetV0ReaderName("ConvGammaAODProduction");
    if (fEventCuts->InitializeCutsFromCutString(cutnumberEvent.Data())) {
      fV0ReaderV1->SetEventCuts(fEventCuts);
    }
  }

  if (cutnumberPhoton != "") {
    fCuts = new AliConversionPhotonCuts(cutnumberPhoton.Data(),
                                        cutnumberPhoton.Data());
    fCuts->SetIsHeavyIon(false);
    fCuts->SetV0ReaderName("ConvGammaAODProduction");
    if (fCuts->InitializeCutsFromCutString(cutnumberPhoton.Data())) {
      fV0ReaderV1->SetConversionCuts(fCuts);
    }
  }
  fV0ReaderV1->Init();
  AliLog::SetGlobalLogLevel(AliLog::kFatal);

  // connect input V0Reader
  mgr->AddTask(fV0ReaderV1);
  mgr->ConnectInput(fV0ReaderV1, 0, cinput);

  AliLog::SetGlobalLogLevel(AliLog::kInfo);

  //================================================
  //              data containers
  //================================================
  //            find input container
  // below the trunk version
  AliAnalysisDataContainer *coutput =
      mgr->CreateContainer("PCM onflyV0Finder container", TBits::Class(),
                           AliAnalysisManager::kExchangeContainer);

  mgr->ConnectOutput(fV0ReaderV1, 1, coutput);

  return fV0ReaderV1;
}
<|endoftext|>


<commit_before><commit_msg>WaE: unused variable 'aSrcOutRect'<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#define Region QtXRegion

#include <QColor>
#include <QStyle>

#include <kconfig.h>
#include <kglobal.h>
#include <kmenubar.h>
#include <kconfiggroup.h>
#include <kmainwindow.h>
#include <kapplication.h>
#include <ktoolbar.h>

#undef Region

#include "KDESalFrame.hxx"
#include "KDEXLib.hxx"
#include "KDESalGraphics.hxx"

#include <vcl/settings.hxx>
#include <vcl/font.hxx>
#include <tools/color.hxx>

#include <vcl/svdata.hxx>

#include <pspgraphics.h>

#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
#endif

KDESalFrame::KDESalFrame( SalFrame* pParent, sal_uLong nState ) :
    X11SalFrame( pParent, nState )
{
}

void KDESalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
{
    if ( !GetParent() && ! (GetStyle() & SAL_FRAME_STYLE_INTRO) )
    {
        KDEXLib* pXLib = static_cast<KDEXLib*>(GetDisplay()->GetXLib());
        pXLib->doStartup();
    }

    X11SalFrame::Show( bVisible, bNoActivate );
}

/** Helper function to convert colors.
*/
static Color toColor( const QColor &rColor )
{
    return Color( rColor.red(), rColor.green(), rColor.blue() );
}

/** Helper function to read untranslated text entry from KConfig configuration repository.
*/
static OUString readEntryUntranslated( KConfigGroup *pGroup, const char *pKey )
{
    return OUString::createFromAscii( (const char *) pGroup->readEntryUntranslated( pKey ).toAscii() );
}

#if 0
#endif
/** Helper function to add information to Font from QFont.

    Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx).
*/
static Font toFont( const QFont &rQFont, const ::com::sun::star::lang::Locale& rLocale )
{
    psp::FastPrintFontInfo aInfo;
    QFontInfo qFontInfo( rQFont );

    // set family name
    aInfo.m_aFamilyName = String( (const char *) rQFont.family().toUtf8(), RTL_TEXTENCODING_UTF8 );

    // set italic
    aInfo.m_eItalic = ( qFontInfo.italic()? psp::italic::Italic: psp::italic::Upright );

    // set weight
    int nWeight = qFontInfo.weight();
    if ( nWeight <= QFont::Light )
        aInfo.m_eWeight = psp::weight::Light;
    else if ( nWeight <= QFont::Normal )
        aInfo.m_eWeight = psp::weight::Normal;
    else if ( nWeight <= QFont::DemiBold )
        aInfo.m_eWeight = psp::weight::SemiBold;
    else if ( nWeight <= QFont::Bold )
        aInfo.m_eWeight = psp::weight::Bold;
    else
        aInfo.m_eWeight = psp::weight::UltraBold;

    // set width
    int nStretch = rQFont.stretch();
    if ( nStretch <= QFont::UltraCondensed )
        aInfo.m_eWidth = psp::width::UltraCondensed;
    else if ( nStretch <= QFont::ExtraCondensed )
        aInfo.m_eWidth = psp::width::ExtraCondensed;
    else if ( nStretch <= QFont::Condensed )
        aInfo.m_eWidth = psp::width::Condensed;
    else if ( nStretch <= QFont::SemiCondensed )
        aInfo.m_eWidth = psp::width::SemiCondensed;
    else if ( nStretch <= QFont::Unstretched )
        aInfo.m_eWidth = psp::width::Normal;
    else if ( nStretch <= QFont::SemiExpanded )
        aInfo.m_eWidth = psp::width::SemiExpanded;
    else if ( nStretch <= QFont::Expanded )
        aInfo.m_eWidth = psp::width::Expanded;
    else if ( nStretch <= QFont::ExtraExpanded )
        aInfo.m_eWidth = psp::width::ExtraExpanded;
    else
        aInfo.m_eWidth = psp::width::UltraExpanded;

#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "font name BEFORE system match: \"%s\"\n", OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
#endif

    // match font to e.g. resolve "Sans"
    psp::PrintFontManager::get().matchFont( aInfo, rLocale );

#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
             aInfo.m_nID != 0 ? "succeeded" : "failed",
             OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
#endif

    // font height
    int nPointHeight = qFontInfo.pointSize();
    if ( nPointHeight <= 0 )
        nPointHeight = rQFont.pointSize();

    // Create the font
    Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
    if( aInfo.m_eWeight != psp::weight::Unknown )
        aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
    if( aInfo.m_eWidth != psp::width::Unknown )
        aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
    if( aInfo.m_eItalic != psp::italic::Unknown )
        aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
    if( aInfo.m_ePitch != psp::pitch::Unknown )
        aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );

    return aFont;
}

/** Implementation of KDE integration's main method.
*/
void KDESalFrame::UpdateSettings( AllSettings& rSettings )
{
    StyleSettings style( rSettings.GetStyleSettings() );
    bool bSetTitleFont = false;

    // General settings
    QPalette pal = kapp->palette();

    style.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_LARGE );

    style.SetActiveColor(toColor(pal.color(QPalette::Active, QPalette::Window)));
    style.SetDeactiveColor(toColor(pal.color(QPalette::Inactive, QPalette::Window)));

    style.SetActiveColor2(toColor(pal.color(QPalette::Active, QPalette::Window)));
    style.SetDeactiveColor2(toColor(pal.color(QPalette::Inactive, QPalette::Window)));

    style.SetActiveTextColor(toColor(pal.color(QPalette::Active, QPalette::WindowText)));
    style.SetDeactiveTextColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));

    // WM settings
    KConfig *pConfig = KGlobal::config().data();
    if ( pConfig )
    {
        KConfigGroup aGroup = pConfig->group( "WM" );
        const char *pKey;

        pKey = "titleFont";
        if ( aGroup.hasKey( pKey ) )
        {
            Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
            style.SetTitleFont( aFont );
            bSetTitleFont = true;
        }

        aGroup = pConfig->group( "Icons" );

        pKey = "Theme";
        if ( aGroup.hasKey( pKey ) )
            style.SetPreferredSymbolsStyleName( readEntryUntranslated( &aGroup, pKey ) );

        //toolbar
        pKey = "toolbarFont";
        if ( aGroup.hasKey( pKey ) )
        {
            Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
            style.SetToolFont( aFont );
        }
    }

    Color aFore = toColor( pal.color( QPalette::Active, QPalette::WindowText ) );
    Color aBack = toColor( pal.color( QPalette::Active, QPalette::Window ) );
    Color aText = toColor( pal.color( QPalette::Active, QPalette::Text ) );
    Color aBase = toColor( pal.color( QPalette::Active, QPalette::Base ) );
    Color aButn = toColor( pal.color( QPalette::Active, QPalette::ButtonText ) );
    Color aMid = toColor( pal.color( QPalette::Active, QPalette::Mid ) );
    Color aHigh = toColor( pal.color( QPalette::Active, QPalette::Highlight ) );

    // Foreground
    style.SetRadioCheckTextColor( aFore );
    style.SetLabelTextColor( aFore );
    style.SetInfoTextColor( aFore );
    style.SetDialogTextColor( aFore );
    style.SetGroupTextColor( aFore );

    // Text
    style.SetFieldTextColor( aText );
    style.SetFieldRolloverTextColor( aText );
    style.SetWindowTextColor( aText );
    style.SetHelpTextColor( aText );

    // Base
    style.SetFieldColor( aBase );
    style.SetHelpColor( aBase );
    style.SetWindowColor( aBase );
    style.SetActiveTabColor( aBase );

    // Buttons
    style.SetButtonTextColor( aButn );
    style.SetButtonRolloverTextColor( aButn );

    // Disable color
    style.SetDisableColor( aMid );

    // Workspace
    style.SetWorkspaceColor( aMid );

    // Background
    style.Set3DColors( aBack );
    style.SetFaceColor( aBack );
    style.SetInactiveTabColor( aBack );
    style.SetDialogColor( aBack );

    if( aBack == COL_LIGHTGRAY )
        style.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
    else
    {
        Color aColor2 = style.GetLightColor();
        style.
            SetCheckedColor( Color( (sal_uInt8)(((sal_uInt16)aBack.GetRed()+(sal_uInt16)aColor2.GetRed())/2),
                        (sal_uInt8)(((sal_uInt16)aBack.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2),
                        (sal_uInt8)(((sal_uInt16)aBack.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2)
                        ) );
    }

    // Selection
    style.SetHighlightColor( aHigh );
    style.SetHighlightTextColor( toColor(pal.color( QPalette::HighlightedText))  );

    // Font
    Font aFont = toFont( kapp->font(), rSettings.GetUILocale() );

    style.SetAppFont( aFont );
    style.SetHelpFont( aFont );

    style.SetMenuFont( aFont ); // will be changed according to pMenuBar
    //style.SetToolFont( aFont ); //already set above
    style.SetLabelFont( aFont );
    style.SetInfoFont( aFont );
    style.SetRadioCheckFont( aFont );
    style.SetPushButtonFont( aFont );
    style.SetFieldFont( aFont );
    style.SetIconFont( aFont );
    style.SetGroupFont( aFont );

    aFont.SetWeight( WEIGHT_BOLD );
    if( !bSetTitleFont )
    {
        style.SetTitleFont( aFont );
    }
    style.SetFloatTitleFont( aFont );

    int flash_time = QApplication::cursorFlashTime();
    style.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME );

    // Menu
    style.SetSkipDisabledInMenus( TRUE );
    KMenuBar* pMenuBar = new KMenuBar();
    if ( pMenuBar )
    {
        // Color
        QPalette qMenuCG = pMenuBar->palette();

        // Menu text and background color, theme specific
        Color aMenuFore = toColor( qMenuCG.color( QPalette::WindowText ) );
        Color aMenuBack = toColor( qMenuCG.color( QPalette::Window ) );

        aMenuFore = toColor( qMenuCG.color( QPalette::ButtonText ) );
        aMenuBack = toColor( qMenuCG.color( QPalette::Button ) );

        style.SetMenuTextColor( aMenuFore );
        style.SetMenuBarTextColor( aMenuFore );
        style.SetMenuColor( aMenuBack );
        style.SetMenuBarColor( aMenuBack );

        style.SetMenuHighlightColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) );

        style.SetMenuHighlightTextColor( aMenuFore );

        // set special menubar higlight text color
        if ( kapp->style()->inherits( "HighContrastStyle" ) )
            ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.color( QPalette::HighlightedText ) );
        else
            ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;

        // Font
        aFont = toFont( pMenuBar->font(), rSettings.GetUILocale() );
        style.SetMenuFont( aFont );
    }

    delete pMenuBar;

    // Scroll bar size
    style.SetScrollBarSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );

    rSettings.SetStyleSettings( style );
}

void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics )
{
    for( int i = 0; i < nMaxGraphics; i++ )
    {
        if( m_aGraphics[i].pGraphics == pGraphics )
        {
            m_aGraphics[i].bInUse = false;
            break;
        }
    }
}

void KDESalFrame::updateGraphics( bool bClear )
{
    Drawable aDrawable = bClear ? None : GetWindow();
    for( int i = 0; i < nMaxGraphics; i++ )
    {
        if( m_aGraphics[i].bInUse )
            m_aGraphics[i].pGraphics->SetDrawable( aDrawable, GetScreenNumber() );
    }
}

KDESalFrame::~KDESalFrame()
{
}

KDESalFrame::GraphicsHolder::~GraphicsHolder()
{
    delete pGraphics;
}

SalGraphics* KDESalFrame::GetGraphics()
{
    if( GetWindow() )
    {
        for( int i = 0; i < nMaxGraphics; i++ )
        {
            if( ! m_aGraphics[i].bInUse )
            {
                m_aGraphics[i].bInUse = true;
                if( ! m_aGraphics[i].pGraphics )
                {
                    m_aGraphics[i].pGraphics = new KDESalGraphics();
                    m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() );
                }
                return m_aGraphics[i].pGraphics;
            }
        }
    }

    return NULL;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>define minimal scrollbar slider size for KDE4<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#define Region QtXRegion

#include <QColor>
#include <QStyle>

#include <kconfig.h>
#include <kglobal.h>
#include <kmenubar.h>
#include <kconfiggroup.h>
#include <kmainwindow.h>
#include <kapplication.h>
#include <ktoolbar.h>

#undef Region

#include "KDESalFrame.hxx"
#include "KDEXLib.hxx"
#include "KDESalGraphics.hxx"

#include <vcl/settings.hxx>
#include <vcl/font.hxx>
#include <tools/color.hxx>

#include <vcl/svdata.hxx>

#include <pspgraphics.h>

#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
#endif

KDESalFrame::KDESalFrame( SalFrame* pParent, sal_uLong nState ) :
    X11SalFrame( pParent, nState )
{
}

void KDESalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
{
    if ( !GetParent() && ! (GetStyle() & SAL_FRAME_STYLE_INTRO) )
    {
        KDEXLib* pXLib = static_cast<KDEXLib*>(GetDisplay()->GetXLib());
        pXLib->doStartup();
    }

    X11SalFrame::Show( bVisible, bNoActivate );
}

/** Helper function to convert colors.
*/
static Color toColor( const QColor &rColor )
{
    return Color( rColor.red(), rColor.green(), rColor.blue() );
}

/** Helper function to read untranslated text entry from KConfig configuration repository.
*/
static OUString readEntryUntranslated( KConfigGroup *pGroup, const char *pKey )
{
    return OUString::createFromAscii( (const char *) pGroup->readEntryUntranslated( pKey ).toAscii() );
}

#if 0
#endif
/** Helper function to add information to Font from QFont.

    Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx).
*/
static Font toFont( const QFont &rQFont, const ::com::sun::star::lang::Locale& rLocale )
{
    psp::FastPrintFontInfo aInfo;
    QFontInfo qFontInfo( rQFont );

    // set family name
    aInfo.m_aFamilyName = String( (const char *) rQFont.family().toUtf8(), RTL_TEXTENCODING_UTF8 );

    // set italic
    aInfo.m_eItalic = ( qFontInfo.italic()? psp::italic::Italic: psp::italic::Upright );

    // set weight
    int nWeight = qFontInfo.weight();
    if ( nWeight <= QFont::Light )
        aInfo.m_eWeight = psp::weight::Light;
    else if ( nWeight <= QFont::Normal )
        aInfo.m_eWeight = psp::weight::Normal;
    else if ( nWeight <= QFont::DemiBold )
        aInfo.m_eWeight = psp::weight::SemiBold;
    else if ( nWeight <= QFont::Bold )
        aInfo.m_eWeight = psp::weight::Bold;
    else
        aInfo.m_eWeight = psp::weight::UltraBold;

    // set width
    int nStretch = rQFont.stretch();
    if ( nStretch <= QFont::UltraCondensed )
        aInfo.m_eWidth = psp::width::UltraCondensed;
    else if ( nStretch <= QFont::ExtraCondensed )
        aInfo.m_eWidth = psp::width::ExtraCondensed;
    else if ( nStretch <= QFont::Condensed )
        aInfo.m_eWidth = psp::width::Condensed;
    else if ( nStretch <= QFont::SemiCondensed )
        aInfo.m_eWidth = psp::width::SemiCondensed;
    else if ( nStretch <= QFont::Unstretched )
        aInfo.m_eWidth = psp::width::Normal;
    else if ( nStretch <= QFont::SemiExpanded )
        aInfo.m_eWidth = psp::width::SemiExpanded;
    else if ( nStretch <= QFont::Expanded )
        aInfo.m_eWidth = psp::width::Expanded;
    else if ( nStretch <= QFont::ExtraExpanded )
        aInfo.m_eWidth = psp::width::ExtraExpanded;
    else
        aInfo.m_eWidth = psp::width::UltraExpanded;

#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "font name BEFORE system match: \"%s\"\n", OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
#endif

    // match font to e.g. resolve "Sans"
    psp::PrintFontManager::get().matchFont( aInfo, rLocale );

#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
             aInfo.m_nID != 0 ? "succeeded" : "failed",
             OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
#endif

    // font height
    int nPointHeight = qFontInfo.pointSize();
    if ( nPointHeight <= 0 )
        nPointHeight = rQFont.pointSize();

    // Create the font
    Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
    if( aInfo.m_eWeight != psp::weight::Unknown )
        aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
    if( aInfo.m_eWidth != psp::width::Unknown )
        aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
    if( aInfo.m_eItalic != psp::italic::Unknown )
        aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
    if( aInfo.m_ePitch != psp::pitch::Unknown )
        aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );

    return aFont;
}

/** Implementation of KDE integration's main method.
*/
void KDESalFrame::UpdateSettings( AllSettings& rSettings )
{
    StyleSettings style( rSettings.GetStyleSettings() );
    bool bSetTitleFont = false;

    // General settings
    QPalette pal = kapp->palette();

    style.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_LARGE );

    style.SetActiveColor(toColor(pal.color(QPalette::Active, QPalette::Window)));
    style.SetDeactiveColor(toColor(pal.color(QPalette::Inactive, QPalette::Window)));

    style.SetActiveColor2(toColor(pal.color(QPalette::Active, QPalette::Window)));
    style.SetDeactiveColor2(toColor(pal.color(QPalette::Inactive, QPalette::Window)));

    style.SetActiveTextColor(toColor(pal.color(QPalette::Active, QPalette::WindowText)));
    style.SetDeactiveTextColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));

    // WM settings
    KConfig *pConfig = KGlobal::config().data();
    if ( pConfig )
    {
        KConfigGroup aGroup = pConfig->group( "WM" );
        const char *pKey;

        pKey = "titleFont";
        if ( aGroup.hasKey( pKey ) )
        {
            Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
            style.SetTitleFont( aFont );
            bSetTitleFont = true;
        }

        aGroup = pConfig->group( "Icons" );

        pKey = "Theme";
        if ( aGroup.hasKey( pKey ) )
            style.SetPreferredSymbolsStyleName( readEntryUntranslated( &aGroup, pKey ) );

        //toolbar
        pKey = "toolbarFont";
        if ( aGroup.hasKey( pKey ) )
        {
            Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
            style.SetToolFont( aFont );
        }
    }

    Color aFore = toColor( pal.color( QPalette::Active, QPalette::WindowText ) );
    Color aBack = toColor( pal.color( QPalette::Active, QPalette::Window ) );
    Color aText = toColor( pal.color( QPalette::Active, QPalette::Text ) );
    Color aBase = toColor( pal.color( QPalette::Active, QPalette::Base ) );
    Color aButn = toColor( pal.color( QPalette::Active, QPalette::ButtonText ) );
    Color aMid = toColor( pal.color( QPalette::Active, QPalette::Mid ) );
    Color aHigh = toColor( pal.color( QPalette::Active, QPalette::Highlight ) );

    // Foreground
    style.SetRadioCheckTextColor( aFore );
    style.SetLabelTextColor( aFore );
    style.SetInfoTextColor( aFore );
    style.SetDialogTextColor( aFore );
    style.SetGroupTextColor( aFore );

    // Text
    style.SetFieldTextColor( aText );
    style.SetFieldRolloverTextColor( aText );
    style.SetWindowTextColor( aText );
    style.SetHelpTextColor( aText );

    // Base
    style.SetFieldColor( aBase );
    style.SetHelpColor( aBase );
    style.SetWindowColor( aBase );
    style.SetActiveTabColor( aBase );

    // Buttons
    style.SetButtonTextColor( aButn );
    style.SetButtonRolloverTextColor( aButn );

    // Disable color
    style.SetDisableColor( aMid );

    // Workspace
    style.SetWorkspaceColor( aMid );

    // Background
    style.Set3DColors( aBack );
    style.SetFaceColor( aBack );
    style.SetInactiveTabColor( aBack );
    style.SetDialogColor( aBack );

    if( aBack == COL_LIGHTGRAY )
        style.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
    else
    {
        Color aColor2 = style.GetLightColor();
        style.
            SetCheckedColor( Color( (sal_uInt8)(((sal_uInt16)aBack.GetRed()+(sal_uInt16)aColor2.GetRed())/2),
                        (sal_uInt8)(((sal_uInt16)aBack.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2),
                        (sal_uInt8)(((sal_uInt16)aBack.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2)
                        ) );
    }

    // Selection
    style.SetHighlightColor( aHigh );
    style.SetHighlightTextColor( toColor(pal.color( QPalette::HighlightedText))  );

    // Font
    Font aFont = toFont( kapp->font(), rSettings.GetUILocale() );

    style.SetAppFont( aFont );
    style.SetHelpFont( aFont );

    style.SetMenuFont( aFont ); // will be changed according to pMenuBar
    //style.SetToolFont( aFont ); //already set above
    style.SetLabelFont( aFont );
    style.SetInfoFont( aFont );
    style.SetRadioCheckFont( aFont );
    style.SetPushButtonFont( aFont );
    style.SetFieldFont( aFont );
    style.SetIconFont( aFont );
    style.SetGroupFont( aFont );

    aFont.SetWeight( WEIGHT_BOLD );
    if( !bSetTitleFont )
    {
        style.SetTitleFont( aFont );
    }
    style.SetFloatTitleFont( aFont );

    int flash_time = QApplication::cursorFlashTime();
    style.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME );

    // Menu
    style.SetSkipDisabledInMenus( TRUE );
    KMenuBar* pMenuBar = new KMenuBar();
    if ( pMenuBar )
    {
        // Color
        QPalette qMenuCG = pMenuBar->palette();

        // Menu text and background color, theme specific
        Color aMenuFore = toColor( qMenuCG.color( QPalette::WindowText ) );
        Color aMenuBack = toColor( qMenuCG.color( QPalette::Window ) );

        aMenuFore = toColor( qMenuCG.color( QPalette::ButtonText ) );
        aMenuBack = toColor( qMenuCG.color( QPalette::Button ) );

        style.SetMenuTextColor( aMenuFore );
        style.SetMenuBarTextColor( aMenuFore );
        style.SetMenuColor( aMenuBack );
        style.SetMenuBarColor( aMenuBack );

        style.SetMenuHighlightColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) );

        style.SetMenuHighlightTextColor( aMenuFore );

        // set special menubar higlight text color
        if ( kapp->style()->inherits( "HighContrastStyle" ) )
            ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.color( QPalette::HighlightedText ) );
        else
            ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;

        // Font
        aFont = toFont( pMenuBar->font(), rSettings.GetUILocale() );
        style.SetMenuFont( aFont );
    }

    delete pMenuBar;

    // Scroll bar size
    style.SetScrollBarSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
    style.SetMinThumbSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarSliderMin ));

    rSettings.SetStyleSettings( style );
}

void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics )
{
    for( int i = 0; i < nMaxGraphics; i++ )
    {
        if( m_aGraphics[i].pGraphics == pGraphics )
        {
            m_aGraphics[i].bInUse = false;
            break;
        }
    }
}

void KDESalFrame::updateGraphics( bool bClear )
{
    Drawable aDrawable = bClear ? None : GetWindow();
    for( int i = 0; i < nMaxGraphics; i++ )
    {
        if( m_aGraphics[i].bInUse )
            m_aGraphics[i].pGraphics->SetDrawable( aDrawable, GetScreenNumber() );
    }
}

KDESalFrame::~KDESalFrame()
{
}

KDESalFrame::GraphicsHolder::~GraphicsHolder()
{
    delete pGraphics;
}

SalGraphics* KDESalFrame::GetGraphics()
{
    if( GetWindow() )
    {
        for( int i = 0; i < nMaxGraphics; i++ )
        {
            if( ! m_aGraphics[i].bInUse )
            {
                m_aGraphics[i].bInUse = true;
                if( ! m_aGraphics[i].pGraphics )
                {
                    m_aGraphics[i].pGraphics = new KDESalGraphics();
                    m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() );
                }
                return m_aGraphics[i].pGraphics;
            }
        }
    }

    return NULL;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// $Id$
//
// Jet embedding task.
//
// Author: S.Aiola, C.Loizides

#include "AliJetEmbeddingFromGenTask.h"

#include <TClonesArray.h>
#include <TFolder.h>
#include <TLorentzVector.h>
#include <TParticle.h>
#include <TParticlePDG.h>
#include <TRandom3.h>
#include <TProfile.h>
#include "AliAnalysisManager.h"
#include "AliEMCALDigit.h"
#include "AliEMCALGeometry.h"
#include "AliEMCALRecPoint.h"
#include "AliGenerator.h"
#include "AliHeader.h"
#include "AliLog.h"
#include "AliPicoTrack.h"
#include "AliRun.h"
#include "AliRunLoader.h"
#include "AliStack.h"
#include "AliStack.h"
#include "AliVCluster.h"
#include "AliVEvent.h"
#include "AliGenPythiaEventHeader.h"
#include "AliStackPartonInfo.h"

ClassImp(AliJetEmbeddingFromGenTask)

//________________________________________________________________________
AliJetEmbeddingFromGenTask::AliJetEmbeddingFromGenTask() :
  AliJetModelBaseTask("AliJetEmbeddingFromGenTask"),
  fGen(0),
  fMassless(kFALSE),
  fChargedOnly(kFALSE),
  fHistPt(0),
  fHistEtaPhi(0),
  fHistTrials(0),
  fHistXsection(0),
  fHistPtHard(0)
{
  // Default constructor.
  SetSuffix("EmbeddedFromGen");
}

//________________________________________________________________________
AliJetEmbeddingFromGenTask::AliJetEmbeddingFromGenTask(const char *name, Bool_t drawqa) :
  AliJetModelBaseTask(name,drawqa),
  fGen(0),
  fMassless(kFALSE),
  fChargedOnly(kFALSE),
  fHistPt(0),
  fHistEtaPhi(0),
  fHistTrials(0),
  fHistXsection(0),
  fHistPtHard(0)
{
  // Standard constructor.
  SetSuffix("EmbeddedFromGen");
}

//________________________________________________________________________
AliJetEmbeddingFromGenTask::~AliJetEmbeddingFromGenTask()
{
  // Destructor
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::UserCreateOutputObjects()
{
  // Create user output.

  if (!fQAhistos)
    return;

  AliJetModelBaseTask::UserCreateOutputObjects();

  fHistPt = new TH1F("fHistpt","fHistPt;#it{p}_{T};N",100,0.,100.);
  fOutput->Add(fHistPt);

  fHistEtaPhi = new TH2F("fHistEtapHI","fHistEtaPhi;#eta;#varphi",100,-3.,3.,100.,0.,TMath::TwoPi());
  fOutput->Add(fHistEtaPhi);

  fHistTrials = new TH1F("fHistTrials", "fHistTrials", 1, 0, 1);
  fHistTrials->GetYaxis()->SetTitle("trials");
  fOutput->Add(fHistTrials);

  fHistXsection = new TProfile("fHistXsection", "fHistXsection", 1, 0, 1);
  fHistXsection->GetYaxis()->SetTitle("xsection");
  fOutput->Add(fHistXsection);

  fHistPtHard = new TH1F("fHistPtHard", "fHistPtHard", 500, 0., 500.);
  fHistPtHard->GetXaxis()->SetTitle("p_{T,hard} (GeV/c)");
  fHistPtHard->GetYaxis()->SetTitle("counts");
  fOutput->Add(fHistPtHard);

  PostData(1, fOutput);
}

//________________________________________________________________________
Bool_t AliJetEmbeddingFromGenTask::ExecOnce()
{
  // Exec only once.

  if (!gAlice) {
    new AliRun("gAlice","The ALICE Off-line Simulation Framework");
    delete gRandom;
    gRandom = new TRandom3(0);
  }

  TFolder *folder = new TFolder(GetName(),GetName());
  AliRunLoader *rl = new AliRunLoader(folder);
  rl->MakeHeader();
  rl->MakeStack();
  AliStack *stack = rl->Stack();
  fGen->SetStack(stack);
  fGen->Init();

  if (!(InputEvent()->FindListObject(fTracksName))) {
    fOutTracks = new TClonesArray("AliPicoTrack", 1000);
    fOutTracks->SetName(fTracksName);
    InputEvent()->AddObject(fOutTracks);
    fNTracks = 0;
  }

  if (!(InputEvent()->FindListObject(fPartonInfoName))) {
  fStackPartonInfo = new AliStackPartonInfo("PartonsInfo");
  fStackPartonInfo->SetName(fPartonInfoName);
  InputEvent()->AddObject(fStackPartonInfo);
  }
  return kTRUE;
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::Run()
{
  // Embed particles.

  if (fCopyArray)
    CopyTracks();

  AliStack *stack = fGen->GetStack();
  stack->Reset();
  fGen->Generate();
  const Int_t nprim = stack->GetNprimary();
  // reject if partons are missing from stack for some reason
  if(nprim < 8) return;
  TParticle *part6 = stack->Particle(6);
  TParticle *part7 = stack->Particle(7);

  fStackPartonInfo->SetPartonFlag6(TMath::Abs(part6->GetPdgCode()));
  fStackPartonInfo->SetPartonPt6(part6->Pt());
  fStackPartonInfo->SetPartonEta6(part6->Eta());
  fStackPartonInfo->SetPartonPhi6(part6->Phi());

  fStackPartonInfo->SetPartonFlag7(TMath::Abs(part7->GetPdgCode()));
  fStackPartonInfo->SetPartonPt7(part7->Pt());
  fStackPartonInfo->SetPartonEta7(part7->Eta());
  fStackPartonInfo->SetPartonPhi7(part7->Phi());

  for (Int_t i=0;i<nprim;++i) {
    if (!stack->IsPhysicalPrimary(i))
      continue;
    TParticle *part = stack->Particle(i);
    TParticlePDG *pdg = part->GetPDG(1);
    if (!pdg)
      continue;
    Int_t c = (Int_t)(TMath::Abs(pdg->Charge()));
    if (fChargedOnly && c==0)  continue;
    Double_t pt = part->Pt();
    Double_t eta = part->Eta();
    Double_t phi = part->Phi();
    if (eta<fEtaMin)
      continue;
    if (eta>fEtaMax)
      continue;
    if (phi<fPhiMin)
      continue;
    if (phi>fPhiMax)
      continue;
    if (pt<fPtMin)
      continue;
    if (pt>fPtMax)
      continue;
    Double_t mass = part->GetMass();
    if(fMassless) mass = 0.;
    fHistPt->Fill(pt);
    fHistEtaPhi->Fill(eta,phi);
    AddTrack(pt, eta, phi,0,0,0,0,0,0,c,mass);
  }

  FillPythiaHistograms();
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::FillPythiaHistograms() {
  //Get PYTHIA info: pt-hard, x-section, trials

  if (!fQAhistos)
    return;

  AliRunLoader *rl = AliRunLoader::Instance();
  AliGenPythiaEventHeader *genPH = dynamic_cast<AliGenPythiaEventHeader*>(rl->GetHeader()->GenEventHeader());
  if(genPH) {
    Float_t xsec = genPH->GetXsection();
    Int_t trials = genPH->Trials();
    Float_t pthard = genPH->GetPtHard();

    fHistXsection->Fill(0.5,xsec);
    fHistTrials->Fill(0.5,trials);
    fHistPtHard->Fill(pthard);
  }
}
<commit_msg>correct Run Loader<commit_after>// $Id$
//
// Jet embedding task.
//
// Author: S.Aiola, C.Loizides

#include "AliJetEmbeddingFromGenTask.h"

#include <TClonesArray.h>
#include <TFolder.h>
#include <TLorentzVector.h>
#include <TParticle.h>
#include <TParticlePDG.h>
#include <TRandom3.h>
#include <TProfile.h>
#include "AliAnalysisManager.h"
#include "AliEMCALDigit.h"
#include "AliEMCALGeometry.h"
#include "AliEMCALRecPoint.h"
#include "AliGenerator.h"
#include "AliHeader.h"
#include "AliLog.h"
#include "AliPicoTrack.h"
#include "AliRun.h"
#include "AliRunLoader.h"
#include "AliStack.h"
#include "AliStack.h"
#include "AliVCluster.h"
#include "AliVEvent.h"
#include "AliGenPythiaEventHeader.h"
#include "AliStackPartonInfo.h"

ClassImp(AliJetEmbeddingFromGenTask)

//________________________________________________________________________
AliJetEmbeddingFromGenTask::AliJetEmbeddingFromGenTask() :
  AliJetModelBaseTask("AliJetEmbeddingFromGenTask"),
  fGen(0),
  fMassless(kFALSE),
  fChargedOnly(kFALSE),
  fHistPt(0),
  fHistEtaPhi(0),
  fHistTrials(0),
  fHistXsection(0),
  fHistPtHard(0)
{
  // Default constructor.
  SetSuffix("EmbeddedFromGen");
}

//________________________________________________________________________
AliJetEmbeddingFromGenTask::AliJetEmbeddingFromGenTask(const char *name, Bool_t drawqa) :
  AliJetModelBaseTask(name,drawqa),
  fGen(0),
  fMassless(kFALSE),
  fChargedOnly(kFALSE),
  fHistPt(0),
  fHistEtaPhi(0),
  fHistTrials(0),
  fHistXsection(0),
  fHistPtHard(0)
{
  // Standard constructor.
  SetSuffix("EmbeddedFromGen");
}

//________________________________________________________________________
AliJetEmbeddingFromGenTask::~AliJetEmbeddingFromGenTask()
{
  // Destructor
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::UserCreateOutputObjects()
{
  // Create user output.

  if (!fQAhistos)
    return;

  AliJetModelBaseTask::UserCreateOutputObjects();

  fHistPt = new TH1F("fHistpt","fHistPt;#it{p}_{T};N",100,0.,100.);
  fOutput->Add(fHistPt);

  fHistEtaPhi = new TH2F("fHistEtapHI","fHistEtaPhi;#eta;#varphi",100,-3.,3.,100.,0.,TMath::TwoPi());
  fOutput->Add(fHistEtaPhi);

  fHistTrials = new TH1F("fHistTrials", "fHistTrials", 1, 0, 1);
  fHistTrials->GetYaxis()->SetTitle("trials");
  fOutput->Add(fHistTrials);

  fHistXsection = new TProfile("fHistXsection", "fHistXsection", 1, 0, 1);
  fHistXsection->GetYaxis()->SetTitle("xsection");
  fOutput->Add(fHistXsection);

  fHistPtHard = new TH1F("fHistPtHard", "fHistPtHard", 500, 0., 500.);
  fHistPtHard->GetXaxis()->SetTitle("p_{T,hard} (GeV/c)");
  fHistPtHard->GetYaxis()->SetTitle("counts");
  fOutput->Add(fHistPtHard);

  PostData(1, fOutput);
}

//________________________________________________________________________
Bool_t AliJetEmbeddingFromGenTask::ExecOnce()
{
  // Exec only once.

  if (!gAlice) {
    new AliRun("gAlice","The ALICE Off-line Simulation Framework");
    delete gRandom;
    gRandom = new TRandom3(0);
  }

  TFolder *folder = new TFolder(GetName(),GetName());
  AliRunLoader *rl = new AliRunLoader(folder);
  gAlice->SetRunLoader(rl);
  rl->MakeHeader();
  rl->MakeStack();
  AliStack *stack = rl->Stack();
  fGen->SetStack(stack);
  fGen->Init();

  if (!(InputEvent()->FindListObject(fTracksName))) {
    fOutTracks = new TClonesArray("AliPicoTrack", 1000);
    fOutTracks->SetName(fTracksName);
    InputEvent()->AddObject(fOutTracks);
    fNTracks = 0;
  }

  if (!(InputEvent()->FindListObject(fPartonInfoName))) {
  fStackPartonInfo = new AliStackPartonInfo("PartonsInfo");
  fStackPartonInfo->SetName(fPartonInfoName);
  InputEvent()->AddObject(fStackPartonInfo);
  }
  return kTRUE;
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::Run()
{
  // Embed particles.

  if (fCopyArray)
    CopyTracks();

  AliStack *stack = fGen->GetStack();
  stack->Reset();
  fGen->Generate();
  const Int_t nprim = stack->GetNprimary();
  // reject if partons are missing from stack for some reason
  if(nprim < 8) return;
  TParticle *part6 = stack->Particle(6);
  TParticle *part7 = stack->Particle(7);

  fStackPartonInfo->SetPartonFlag6(TMath::Abs(part6->GetPdgCode()));
  fStackPartonInfo->SetPartonPt6(part6->Pt());
  fStackPartonInfo->SetPartonEta6(part6->Eta());
  fStackPartonInfo->SetPartonPhi6(part6->Phi());

  fStackPartonInfo->SetPartonFlag7(TMath::Abs(part7->GetPdgCode()));
  fStackPartonInfo->SetPartonPt7(part7->Pt());
  fStackPartonInfo->SetPartonEta7(part7->Eta());
  fStackPartonInfo->SetPartonPhi7(part7->Phi());

  for (Int_t i=0;i<nprim;++i) {
    if (!stack->IsPhysicalPrimary(i))
      continue;
    TParticle *part = stack->Particle(i);
    TParticlePDG *pdg = part->GetPDG(1);
    if (!pdg)
      continue;
    Int_t c = (Int_t)(TMath::Abs(pdg->Charge()));
    if (fChargedOnly && c==0)  continue;
    Double_t pt = part->Pt();
    Double_t eta = part->Eta();
    Double_t phi = part->Phi();
    if (eta<fEtaMin)
      continue;
    if (eta>fEtaMax)
      continue;
    if (phi<fPhiMin)
      continue;
    if (phi>fPhiMax)
      continue;
    if (pt<fPtMin)
      continue;
    if (pt>fPtMax)
      continue;
    Double_t mass = part->GetMass();
    if(fMassless) mass = 0.;
    fHistPt->Fill(pt);
    fHistEtaPhi->Fill(eta,phi);
    AddTrack(pt, eta, phi,0,0,0,0,0,0,c,mass);
  }

  FillPythiaHistograms();
}

//________________________________________________________________________
void AliJetEmbeddingFromGenTask::FillPythiaHistograms() {
  //Get PYTHIA info: pt-hard, x-section, trials

  if (!fQAhistos)
    return;

  AliRunLoader *rl = AliRunLoader::Instance();
  AliGenPythiaEventHeader *genPH = dynamic_cast<AliGenPythiaEventHeader*>(rl->GetHeader()->GenEventHeader());
  if(genPH) {
    Float_t xsec = genPH->GetXsection();
    Int_t trials = genPH->Trials();
    Float_t pthard = genPH->GetPtHard();

    fHistXsection->Fill(0.5,xsec);
    fHistTrials->Fill(0.5,trials);
    fHistPtHard->Fill(pthard);
  }
}
<|endoftext|>


<commit_before>#include "MeshUtility.h"

using namespace Rendering;
using namespace Rendering::Geometry;
using namespace Intersection;
using namespace Rendering::Manager;
using namespace Core;
using namespace Math;

const Transform& MeshUtility::_FindTransform(const Mesh& mesh, const TransformPool& transformPool)
{
	auto id = mesh.GetObjectID();
	uint findIdx = transformPool.GetIndexer().Find(id.Literal());
	assert(findIdx != TransformPool::IndexerType::FailIndex());

	return transformPool.Get(findIdx);
}

void MeshUtility::_SortTransparentMesh(std::vector<const Mesh*>& refMeshes,
						 				const Vector3& viewDir, const TransformPool& transformPool)
{
	auto SortingByDistance = [&transformPool, &viewDir](const Mesh* left, const Mesh* right) -> bool
	{
		auto SortKey = [&viewDir, &transformPool](const Mesh* mesh) -> float
		{
			auto& pos = _FindTransform(*mesh, transformPool).GetWorldPosition();
			return Vector3::Dot(pos, viewDir);
		};

		return SortKey(left) < SortKey(right);
	};

	std::sort(refMeshes.begin(), refMeshes.end(), SortingByDistance);
}
<commit_msg>MeshUtility.cpp - std::vector<const Mesh*> -> TransparentMeshPtrs<commit_after>#include "MeshUtility.h"

using namespace Rendering;
using namespace Rendering::Geometry;
using namespace Intersection;
using namespace Rendering::Manager;
using namespace Core;
using namespace Math;

const Transform& MeshUtility::_FindTransform(const Mesh& mesh, const TransformPool& transformPool)
{
	auto id = mesh.GetObjectID();
	uint findIdx = transformPool.GetIndexer().Find(id.Literal());
	assert(findIdx != TransformPool::IndexerType::FailIndex());

	return transformPool.Get(findIdx);
}

void MeshUtility::_SortTransparentMesh(TransparentMeshPtrs& refMeshes,
						 				const Vector3& viewDir, const TransformPool& transformPool)
{
	auto SortingByDistance = [&transformPool, &viewDir](const Mesh* left, const Mesh* right) -> bool
	{
		auto SortKey = [&viewDir, &transformPool](const Mesh* mesh) -> float
		{
			auto& pos = _FindTransform(*mesh, transformPool).GetWorldPosition();
			return Vector3::Dot(pos, viewDir);
		};

		return SortKey(left) < SortKey(right);
	};

	std::sort(refMeshes.begin(), refMeshes.end(), SortingByDistance);
}
<|endoftext|>


<commit_before>#include "testing/testing.hpp"

#include "storage/simple_tree.hpp"

namespace
{

template <class TNode>
struct Calculator
{
  size_t count;
  Calculator() : count(0) {}
  void operator()(TNode const &)
  {
    ++count;
  }
};

}

UNIT_TEST(SimpleTree_Smoke)
{
  typedef SimpleTree<int> TreeT;
  TreeT tree;

  tree.Add(4);
  tree.Add(3);
  tree.Add(5);
  tree.Add(2);
  tree.Add(1);
  tree.AddAtDepth(1, 20);  // 1 is parent
  tree.AddAtDepth(1, 10);  // 1 is parent
  tree.AddAtDepth(1, 30);  // 1 is parent

  tree.Sort();
  // test sorting
  TEST_EQUAL(tree.Child(0).Value(), 1, ());
  TEST_EQUAL(tree.Child(1).Value(), 2, ());
  TEST_EQUAL(tree.Child(2).Value(), 3, ());
  TEST_EQUAL(tree.Child(3).Value(), 4, ());
  TEST_EQUAL(tree.Child(4).Value(), 5, ());
  TEST_EQUAL(tree.Child(0).Child(0).Value(), 10, ());
  TEST_EQUAL(tree.Child(0).Child(1).Value(), 20, ());
  TEST_EQUAL(tree.Child(0).Child(2).Value(), 30, ());

  Calculator<TreeT> c1;
  tree.ForEachChild(c1);
  TEST_EQUAL(c1.count, 5, ());

  Calculator<TreeT> c2;
  tree.ForEachDescendant(c2);
  TEST_EQUAL(c2.count, 8, ());

  tree.Clear();
  Calculator<TreeT> c3;
  tree.ForEachDescendant(c3);
  TEST_EQUAL(c3.count, 0, ("Tree should be empty"));
}
<commit_msg>[new downloader] Unit tests on SimpleTree.<commit_after>#include "testing/testing.hpp"

#include "storage/simple_tree.hpp"

namespace
{
template <class TNode>
struct Calculator
{
  size_t count;
  Calculator() : count(0) {}
  void operator()(TNode const &)
  {
    ++count;
  }
};
} // namespace

UNIT_TEST(SimpleTree_Smoke)
{
  typedef SimpleTree<int> TreeT;
  TreeT tree;

  tree.Add(4);
  tree.Add(3);
  tree.Add(5);
  tree.Add(2);
  tree.Add(1);
  tree.AddAtDepth(1, 20);  // 1 is parent
  tree.AddAtDepth(1, 10);  // 1 is parent
  tree.AddAtDepth(1, 30);  // 1 is parent

  // children test
  TEST_EQUAL(tree.Child(0).Value(), 4, ());
  TEST_EQUAL(tree.Child(1).Value(), 3, ());
  TEST_EQUAL(tree.Child(2).Value(), 5, ());
  TEST_EQUAL(tree.Child(3).Value(), 2, ());
  TEST_EQUAL(tree.Child(4).Value(), 1, ());
  TEST_EQUAL(tree.Child(4).Child(0).Value(), 20, ());
  TEST_EQUAL(tree.Child(4).Child(1).Value(), 10, ());
  TEST_EQUAL(tree.Child(4).Child(2).Value(), 30, ());

  // parent test
  TEST(!tree.HasParent(), ());
  TEST(!tree.Child(0).Parent().HasParent(), ());
  TEST_EQUAL(tree.Child(4).Child(0).Parent().Value(), 1, ());
  TEST_EQUAL(tree.Child(4).Child(2).Parent().Value(), 1, ());

  Calculator<TreeT> c1;
  tree.ForEachChild(c1);
  TEST_EQUAL(c1.count, 5, ());

  Calculator<TreeT> c2;
  tree.ForEachDescendant(c2);
  TEST_EQUAL(c2.count, 8, ());

  Calculator<TreeT> c3;
  tree.Child(4).Child(0).ForEachParent(c3);
  TEST_EQUAL(c3.count, 2, ());

  tree.Clear();
  Calculator<TreeT> c4;
  tree.ForEachDescendant(c4);
  TEST_EQUAL(c4.count, 0, ("Tree should be empty"));
}
<|endoftext|>