<commit_before>
#include "nui.h"
#include "nuiDrawerView.h"

static const float SPRING_TOLERANCE = 0.0000000005f;
static const float STIFFNESS = .3f;
static const float PULL_COEF = 4;
static const float MOVE_TOLERANCE = 8;

nuiDrawerView::nuiDrawerView() :
mpLeft(nullptr), mpMain(nullptr), mpRight(nullptr), mOffset(0), mTouched(false), mMoving(false), mOriginalOffset(0), mTargetOffset(0), mEventSink(this), mInteractive(true)
{
  if (SetObjectClass("nuiDrawerView"))
  {
    // Init attributes:
    AddAttribute(new nuiAttribute<bool>
                 (nglString(_T("Interactive")), nuiUnitBoolean,
                  nuiMakeDelegate(this, &nuiDrawerView::GetInteractive),
                  nuiMakeDelegate(this, &nuiDrawerView::SetInteractive)));

    AddAttribute(new nuiAttribute<float>
                 (nglString(_T("AnimRatio")), nuiUnitBoolean,
                  nuiMakeDelegate(this, &nuiDrawerView::GetAnimRatio),
                  nuiMakeDelegate(this, &nuiDrawerView::SetAnimRatio)));
  }

  NUI_ADD_EVENT(LeftOpened);
  NUI_ADD_EVENT(RightOpened);
  NUI_ADD_EVENT(Opened);
  NUI_ADD_EVENT(Closed);

  nuiAnimation::AcquireTimer();
}

nuiDrawerView::~nuiDrawerView()
{
  nuiAnimation::ReleaseTimer();
}

void nuiDrawerView::OpenLeft()
{
  if (!mpLeft)
    return;

  mMoving = false;
  mTouched = false;

  float width = mpLeft->GetIdealRect().GetWidth();
  mTargetOffset = width;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

void nuiDrawerView::OpenRight()
{
  if (!mpRight)
    return;

  mMoving = false;
  mTouched = false;

  float width = mpRight->GetIdealRect().GetWidth();
    mTargetOffset = -width;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

void nuiDrawerView::Close()
{
  mMoving = false;
  mTouched = false;

  mTargetOffset = 0;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::IsOpen() const
{
  return mTargetOffset != 0;
}

bool nuiDrawerView::IsLeftOpen() const
{
  return mTargetOffset > 0;
}

bool nuiDrawerView::IsRightOpen() const
{
  return mTargetOffset < 0;
}

void nuiDrawerView::ToggleLeft()
{
  if (!IsLeftOpen())
    OpenLeft();
  else
    Close();
}

void nuiDrawerView::ToggleRight()
{
  if (!IsRightOpen())
    OpenRight();
  else
    Close();
}

bool nuiDrawerView::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  //NGL_OUT("Set Rect with mOffset %f\n", mOffset);
  if (mpLeft)
  {
    nuiRect r(MIN(mpLeft->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MIN(0, mOffset - r.GetWidth()), 0);
    mpLeft->SetLayout(r);
  }

  if (mpMain)
  {
    nuiRect r(rRect.Size());
    r.Move(mOffset, 0);
    mpMain->SetLayout(r);
  }

  if (mpRight)
  {
    nuiRect r(MIN(mpRight->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MAX(mOffset + rRect.GetWidth(), rRect.GetWidth() - r.GetWidth()), 0);
    mpRight->SetLayout(r);
  }

  return true;
}

nuiRect nuiDrawerView::CalcIdealSize()
{
  return mpMain ? mpMain->GetIdealRect() : nuiRect();
}

bool nuiDrawerView::AddChild(nuiWidgetPtr pWidget)
{
  if (pWidget->GetProperty("Drawer").Compare("left", false) == 0)
  {
    if (mpLeft)
      DelChild(mpLeft);
    mpLeft = pWidget;
  }
  else if (pWidget->GetProperty("Drawer").Compare("right", false) == 0)
  {
    if (mpRight)
      DelChild(mpRight);
    mpRight = pWidget;
  }
  else
  {
    if (mpMain)
      DelChild(mpMain);
    mpMain = pWidget;
  }
  return nuiSimpleContainer::AddChild(pWidget);
}

bool nuiDrawerView::DelChild(nuiWidgetPtr pWidget)
{
  if (pWidget == mpLeft)
    mpLeft = NULL;
  if (pWidget == mpRight)
    mpRight = NULL;
  if (pWidget == mpMain)
    mpMain = NULL;
  return nuiSimpleContainer::DelChild(pWidget);
}

void nuiDrawerView::SetLeft(nuiWidgetPtr pWidget)
{
  if (mpLeft)
    DelChild(mpLeft);
  if (pWidget)
    AddChild(pWidget);
  mpLeft = pWidget;
}

void nuiDrawerView::SetMain(nuiWidgetPtr pWidget)
{
  if (mpMain)
    DelChild(mpMain);
  if (pWidget)
    AddChild(pWidget);
  mpMain = pWidget;
}

void nuiDrawerView::SetRight(nuiWidgetPtr pWidget)
{
  if (mpRight)
    DelChild(mpRight);
  if (pWidget)
    AddChild(pWidget);
  mpRight = pWidget;
}

nuiWidgetPtr nuiDrawerView::GetLeft()
{
  return mpLeft;
}

nuiWidgetPtr nuiDrawerView::GetMain()
{
  return mpMain;
}

nuiWidgetPtr nuiDrawerView::GetRight()
{
  return mpRight;
}

bool nuiDrawerView::PreMouseClicked(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mTouch = rInfo;
    mTouched = true;
    mOriginalOffset = mOffset;
   //NGL_OUT("PreMouseClicked mOriginalOffset = %f\n", mOriginalOffset);
  }
  return false;
}

bool nuiDrawerView::PreMouseUnclicked(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (mStealRefused)
  {
    mTouched = false;
    mMoving = false;
    mStealRefused = false;
    return false;
  }

  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    if (mTouched && !mMoving && mOffset != 0)
    {
      if ((mOffset < 0 && rInfo.X < mRect.GetWidth() + mOffset) || (mOffset > 0 && rInfo.X > mOffset))
      {
        if (mpMain)
        {
          mpMain->DispatchMouseCanceled(this, rInfo);
        }
        mTouched = false;

        mTargetOffset = 0;
        mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);

        return true;
      }
    }
    mTouched = false;
  }
  return false;
}

bool nuiDrawerView::PreMouseMoved(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (mTouched && !mMoving)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      if (StealMouseEvent(rInfo))
      {
        mTouched = false;
        mMoving = true;
        mStealRefused = false;
        return true;
      }
      else
      {
        NGL_LOG("nuiDrawer", NGL_LOG_DEBUG, "PreMouseMoved: StealMouseEvent refused\n");
        mStealRefused = true;
      }
    }
  }
  return false;
}

bool nuiDrawerView::MouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mMoving = false;
    mTouched = false;

    mTouch = rInfo;
    mOriginalOffset = mOffset;

    SetSelected(true);
    // Stop events, just in case...
    mEventSink.DisconnectAll();
  }
  return false;
}

void nuiDrawerView::ReleaseTouch()
{
  mMoving = false;
  mTouched = false;

  if (mOffset < 0)
  {
    // We should we go?
    float width = mpRight->GetIdealRect().GetWidth();
    if (-mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = -width;
    }
  }
  else if (mOffset > 0)
  {
    // We should we go?
    float width = mpLeft->GetIdealRect().GetWidth();
    if (mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = width;
    }
  }
  else
  {
    mTargetOffset = 0;
  }

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::MouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    ReleaseTouch();
    SetSelected(false);
  }
  return false;
}

bool nuiDrawerView::MouseMoved(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    float dx = mTouch.X - rInfo.X;
    mOffset = mOriginalOffset -dx;
    if (mOffset < 0)
    {
      if (!mpRight)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpRight->GetIdealRect().GetWidth();
        if (mOffset < -width)
        {
          // Compute the position with the
          float diff = -mOffset - width ;
          mOffset = -width - PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }
    else
    {
      if (!mpLeft)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpLeft->GetIdealRect().GetWidth();
        if (mOffset > width)
        {
          // Compute the position with the
          float diff = mOffset - width ;
          mOffset = width + PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }

    //NGL_OUT("Mouse moved, new offset = %f\n", mOffset);
    UpdateLayout();
    return true;
  }

  if (mTouched)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      mTouched = false;
      mMoving = true;
    }
  }
  return false;
}

bool nuiDrawerView::MouseCanceled(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    ReleaseTouch();
  }
  SetSelected(false);
  mTouched = false;
  mMoving = false;
  return false;
}

void nuiDrawerView::OnAnimateDrawer(const nuiEvent &rEvent)
{
  float diff = mTargetOffset - mOffset;
  mOffset += diff * mAnimRatio;

  //NGL_OUT(".");
  diff = mTargetOffset - mOffset;
  if (fabs(diff) < 1.0)
  {
    //NGL_OUT("nuiDrawerView Offset Realease Done\n");
    mOffset = mTargetOffset;
    //NGL_OUT("!!!!!!!! Anim end mOffset = %f\n", mOffset);
    mEventSink.DisconnectAll();

    if (IsOpen())
    {
      Opened();
      if (IsLeftOpen())
      {
        LeftOpened();
      }
      else
      {
        RightOpened();
      }
    }
    else
    {
      Closed();
    }
  }

  mOriginalOffset = mOffset;
  UpdateLayout();
}
<commit_msg>better close/toogle/open interactions<commit_after>
#include "nui.h"
#include "nuiDrawerView.h"

static const float SPRING_TOLERANCE = 0.0000000005f;
static const float STIFFNESS = .3f;
static const float PULL_COEF = 4;
static const float MOVE_TOLERANCE = 8;

nuiDrawerView::nuiDrawerView() :
mpLeft(nullptr), mpMain(nullptr), mpRight(nullptr), mOffset(0), mTouched(false), mMoving(false), mOriginalOffset(0), mTargetOffset(0), mEventSink(this), mInteractive(true)
{
  if (SetObjectClass("nuiDrawerView"))
  {
    // Init attributes:
    AddAttribute(new nuiAttribute<bool>
                 ("Interactive", nuiUnitBoolean,
                  nuiMakeDelegate(this, &nuiDrawerView::GetInteractive),
                  nuiMakeDelegate(this, &nuiDrawerView::SetInteractive)));

    AddAttribute(new nuiAttribute<float>
                 ("AnimRatio", nuiUnitBoolean,
                  nuiMakeDelegate(this, &nuiDrawerView::GetAnimRatio),
                  nuiMakeDelegate(this, &nuiDrawerView::SetAnimRatio)));
  }

  NUI_ADD_EVENT(LeftOpened);
  NUI_ADD_EVENT(RightOpened);
  NUI_ADD_EVENT(Opened);
  NUI_ADD_EVENT(Closed);

  nuiAnimation::AcquireTimer();
}

nuiDrawerView::~nuiDrawerView()
{
  nuiAnimation::ReleaseTimer();
}

void nuiDrawerView::OpenLeft()
{
  if (!mpLeft)
    return;

  mMoving = false;
  mTouched = false;
  mStealRefused = false;

  float width = mpLeft->GetIdealRect().GetWidth();
  mTargetOffset = width;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

void nuiDrawerView::OpenRight()
{
  if (!mpRight)
    return;

  mMoving = false;
  mTouched = false;
  mStealRefused = false;

  float width = mpRight->GetIdealRect().GetWidth();
    mTargetOffset = -width;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

void nuiDrawerView::Close()
{
  mMoving = false;
  mTouched = false;
  mStealRefused = false;

  mTargetOffset = 0;

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::IsOpen() const
{
  return mTargetOffset != 0;
}

bool nuiDrawerView::IsLeftOpen() const
{
  return mTargetOffset > 0;
}

bool nuiDrawerView::IsRightOpen() const
{
  return mTargetOffset < 0;
}

void nuiDrawerView::ToggleLeft()
{
  if (!IsLeftOpen())
    OpenLeft();
  else
    Close();
}

void nuiDrawerView::ToggleRight()
{
  if (!IsRightOpen())
    OpenRight();
  else
    Close();
}

bool nuiDrawerView::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  //NGL_OUT("Set Rect with mOffset %f\n", mOffset);
  if (mpLeft)
  {
    nuiRect r(MIN(mpLeft->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MIN(0, mOffset - r.GetWidth()), 0);
    mpLeft->SetLayout(r);
  }

  if (mpMain)
  {
    nuiRect r(rRect.Size());
    r.Move(mOffset, 0);
    mpMain->SetLayout(r);
  }

  if (mpRight)
  {
    nuiRect r(MIN(mpRight->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MAX(mOffset + rRect.GetWidth(), rRect.GetWidth() - r.GetWidth()), 0);
    mpRight->SetLayout(r);
  }

  return true;
}

nuiRect nuiDrawerView::CalcIdealSize()
{
  return mpMain ? mpMain->GetIdealRect() : nuiRect();
}

bool nuiDrawerView::AddChild(nuiWidgetPtr pWidget)
{
  if (pWidget->GetProperty("Drawer").Compare("left", false) == 0)
  {
    if (mpLeft)
      DelChild(mpLeft);
    mpLeft = pWidget;
  }
  else if (pWidget->GetProperty("Drawer").Compare("right", false) == 0)
  {
    if (mpRight)
      DelChild(mpRight);
    mpRight = pWidget;
  }
  else
  {
    if (mpMain)
      DelChild(mpMain);
    mpMain = pWidget;
  }
  return nuiSimpleContainer::AddChild(pWidget);
}

bool nuiDrawerView::DelChild(nuiWidgetPtr pWidget)
{
  if (pWidget == mpLeft)
    mpLeft = NULL;
  if (pWidget == mpRight)
    mpRight = NULL;
  if (pWidget == mpMain)
    mpMain = NULL;
  return nuiSimpleContainer::DelChild(pWidget);
}

void nuiDrawerView::SetLeft(nuiWidgetPtr pWidget)
{
  if (mpLeft)
    DelChild(mpLeft);
  if (pWidget)
    AddChild(pWidget);
  mpLeft = pWidget;
}

void nuiDrawerView::SetMain(nuiWidgetPtr pWidget)
{
  if (mpMain)
    DelChild(mpMain);
  if (pWidget)
    AddChild(pWidget);
  mpMain = pWidget;
}

void nuiDrawerView::SetRight(nuiWidgetPtr pWidget)
{
  if (mpRight)
    DelChild(mpRight);
  if (pWidget)
    AddChild(pWidget);
  mpRight = pWidget;
}

nuiWidgetPtr nuiDrawerView::GetLeft()
{
  return mpLeft;
}

nuiWidgetPtr nuiDrawerView::GetMain()
{
  return mpMain;
}

nuiWidgetPtr nuiDrawerView::GetRight()
{
  return mpRight;
}

bool nuiDrawerView::PreMouseClicked(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mTouch = rInfo;
    mTouched = true;
    mOriginalOffset = mOffset;
   //NGL_OUT("PreMouseClicked mOriginalOffset = %f\n", mOriginalOffset);
  }
  return false;
}

bool nuiDrawerView::PreMouseUnclicked(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (mStealRefused)
  {
    mTouched = false;
    mMoving = false;
    mStealRefused = false;
    return false;
  }

  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    if (mTouched && !mMoving && mOffset != 0)
    {
      if ((mOffset < 0 && rInfo.X < mRect.GetWidth() + mOffset) || (mOffset > 0 && rInfo.X > mOffset))
      {
        if (mpMain)
        {
          mpMain->DispatchMouseCanceled(this, rInfo);
        }
        mTouched = false;

        Close();

        return true;
      }
    }
    mTouched = false;
  }
  return false;
}

bool nuiDrawerView::PreMouseMoved(const nglMouseInfo& rInfo)
{
  if (!mInteractive)
    return false;

  if (mTouched && !mMoving)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      if (StealMouseEvent(rInfo))
      {
        mTouched = false;
        mMoving = true;
        mStealRefused = false;
        return true;
      }
      else
      {
        NGL_LOG("nuiDrawer", NGL_LOG_DEBUG, "PreMouseMoved: StealMouseEvent refused\n");
        mStealRefused = true;
      }
    }
  }
  return false;
}

bool nuiDrawerView::MouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mMoving = false;
    mTouched = false;

    mTouch = rInfo;
    mOriginalOffset = mOffset;

    SetSelected(true);
    // Stop events, just in case...
    mEventSink.DisconnectAll();
  }
  return false;
}

void nuiDrawerView::ReleaseTouch()
{
  mMoving = false;
  mTouched = false;

  if (mOffset < 0)
  {
    // We should we go?
    float width = mpRight->GetIdealRect().GetWidth();
    if (-mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      Close();
      return;
    }
    else
    {
      mTargetOffset = -width;
    }
  }
  else if (mOffset > 0)
  {
    // We should we go?
    float width = mpLeft->GetIdealRect().GetWidth();
    if (mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      Close();
      return;
    }
    else
    {
      mTargetOffset = width;
    }
  }
  else
  {
    mTargetOffset = 0;
  }

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::MouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    ReleaseTouch();
    SetSelected(false);
  }
  return false;
}

bool nuiDrawerView::MouseMoved(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    float dx = mTouch.X - rInfo.X;
    mOffset = mOriginalOffset -dx;
    if (mOffset < 0)
    {
      if (!mpRight)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpRight->GetIdealRect().GetWidth();
        if (mOffset < -width)
        {
          // Compute the position with the
          float diff = -mOffset - width ;
          mOffset = -width - PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }
    else
    {
      if (!mpLeft)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpLeft->GetIdealRect().GetWidth();
        if (mOffset > width)
        {
          // Compute the position with the
          float diff = mOffset - width ;
          mOffset = width + PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }

    //NGL_OUT("Mouse moved, new offset = %f\n", mOffset);
    UpdateLayout();
    return true;
  }

  if (mTouched)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      mTouched = false;
      mMoving = true;
    }
  }
  return false;
}

bool nuiDrawerView::MouseCanceled(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    ReleaseTouch();
  }
  SetSelected(false);
  mTouched = false;
  mMoving = false;
  return false;
}

void nuiDrawerView::OnAnimateDrawer(const nuiEvent &rEvent)
{
  float diff = mTargetOffset - mOffset;
  mOffset += diff * mAnimRatio;

  //NGL_OUT(".");
  diff = mTargetOffset - mOffset;
  if (fabs(diff) < 1.0)
  {
    //NGL_OUT("nuiDrawerView Offset Realease Done\n");
    mOffset = mTargetOffset;
    //NGL_OUT("!!!!!!!! Anim end mOffset = %f\n", mOffset);
    mEventSink.DisconnectAll();

    if (IsOpen())
    {
      Opened();
      if (IsLeftOpen())
      {
        LeftOpened();
      }
      else
      {
        RightOpened();
      }
    }
    else
    {
      Closed();
    }
  }

  mOriginalOffset = mOffset;
  UpdateLayout();
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 */

#include "modules/third_party_perception/fusion.h"

#include <vector>

#include "modules/common/math/polygon2d.h"
#include "modules/common/math/vec2d.h"
#include "modules/third_party_perception/common/third_party_perception_gflags.h"
#include "modules/third_party_perception/common/third_party_perception_util.h"

/**
 * @namespace apollo::third_party_perception::fusion
 * @brief apollo::third_party_perception
 */
namespace apollo {
namespace third_party_perception {
namespace fusion {

using apollo::common::math::Vec2d;
using apollo::perception::PerceptionObstacles;
using apollo::perception::PerceptionObstacle;

std::vector<Vec2d> PerceptionObstacleToVectorVec2d(
    const PerceptionObstacle& obstacle) {
  std::vector<Vec2d> result;
  for (const auto& vertex : obstacle.polygon_point()) {
    result.emplace_back(vertex.x(), vertex.y());
  }
  return result;
}

bool HasOverlap(const PerceptionObstacle& obstacle_1,
                const PerceptionObstacle& obstacle_2) {
  common::math::Polygon2d polygon_1(
      PerceptionObstacleToVectorVec2d(obstacle_1));
  common::math::Polygon2d polygon_2(
      PerceptionObstacleToVectorVec2d(obstacle_2));
  return polygon_1.HasOverlap(polygon_2);
}

bool HasOverlap(const PerceptionObstacle& obstacle,
                const PerceptionObstacles& obstacles) {
  for (const auto& current_obstacle : obstacles.perception_obstacle()) {
    if (HasOverlap(obstacle, current_obstacle)) {
      return true;
    }
  }
  return false;
}

PerceptionObstacles MobileyeRadarFusion(
    const PerceptionObstacles& mobileye_obstacles,
    const PerceptionObstacles& radar_obstacles) {
  PerceptionObstacles mobileye_obstacles_fusion = mobileye_obstacles;
  PerceptionObstacles radar_obstacles_fusion = radar_obstacles;

  for (auto& mobileye_obstacle :
       *(mobileye_obstacles_fusion.mutable_perception_obstacle())) {
    for (auto& radar_obstacle :
         *(radar_obstacles_fusion.mutable_perception_obstacle())) {
      if (HasOverlap(mobileye_obstacle, radar_obstacle)) {
        mobileye_obstacle.set_confidence(0.99);
        radar_obstacle.set_confidence(0.99);
      }
    }
  }

  mobileye_obstacles_fusion.MergeFrom(radar_obstacles_fusion);
  return mobileye_obstacles_fusion;
}

}  // namespace fusion
}  // namespace third_party_perception
}  // namespace apollo
<commit_msg>ThirdParty : Change simple fusion strategy<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 */

#include "modules/third_party_perception/fusion.h"

#include <vector>

#include "modules/common/math/polygon2d.h"
#include "modules/common/math/vec2d.h"
#include "modules/third_party_perception/common/third_party_perception_gflags.h"
#include "modules/third_party_perception/common/third_party_perception_util.h"

/**
 * @namespace apollo::third_party_perception::fusion
 * @brief apollo::third_party_perception
 */
namespace apollo {
namespace third_party_perception {
namespace fusion {

using apollo::common::math::Vec2d;
using apollo::perception::PerceptionObstacle;
using apollo::perception::PerceptionObstacles;

std::vector<Vec2d> PerceptionObstacleToVectorVec2d(
    const PerceptionObstacle& obstacle) {
  std::vector<Vec2d> result;
  for (const auto& vertex : obstacle.polygon_point()) {
    result.emplace_back(vertex.x(), vertex.y());
  }
  return result;
}

bool HasOverlap(const PerceptionObstacle& obstacle_1,
                const PerceptionObstacle& obstacle_2) {
  common::math::Polygon2d polygon_1(
      PerceptionObstacleToVectorVec2d(obstacle_1));
  common::math::Polygon2d polygon_2(
      PerceptionObstacleToVectorVec2d(obstacle_2));
  return polygon_1.HasOverlap(polygon_2);
}

bool HasOverlap(const PerceptionObstacle& obstacle,
                const PerceptionObstacles& obstacles) {
  for (const auto& current_obstacle : obstacles.perception_obstacle()) {
    if (HasOverlap(obstacle, current_obstacle)) {
      return true;
    }
  }
  return false;
}

PerceptionObstacles MobileyeRadarFusion(
    const PerceptionObstacles& mobileye_obstacles,
    const PerceptionObstacles& radar_obstacles) {
  PerceptionObstacles mobileye_obstacles_fusion = mobileye_obstacles;
  PerceptionObstacles radar_obstacles_fusion = radar_obstacles;

  for (auto& mobileye_obstacle :
       *(mobileye_obstacles_fusion.mutable_perception_obstacle())) {
    for (auto& radar_obstacle :
         *(radar_obstacles_fusion.mutable_perception_obstacle())) {
      if (HasOverlap(mobileye_obstacle, radar_obstacle)) {
        mobileye_obstacle.set_confidence(0.99);
        mobileye_obstacle.mutable_velocity()->CopyFrom(
            radar_obstacle.velocity());
      }
    }
  }

  // mobileye_obstacles_fusion.MergeFrom(radar_obstacles_fusion);
  return mobileye_obstacles_fusion;
}

}  // namespace fusion
}  // namespace third_party_perception
}  // namespace apollo
<|endoftext|>


<commit_before>#include "MeshCuboidParameters.h"

// -- Parameters -- //
//
DEFINE_bool(param_optimize_with_non_linear_constraints, true, "");
DEFINE_bool(param_optimize_training_cuboids, true, "");

DEFINE_int32(param_num_sample_point_neighbors, 8, "");
DEFINE_int32(param_min_num_cuboid_sample_points, 10, "");
DEFINE_int32(param_min_num_symmetric_point_pairs, 50, "");
DEFINE_int32(param_num_cuboid_surface_points, 1000, "");
DEFINE_int32(param_intra_cuboid_symmetry_axis, 0, "");
DEFINE_int32(param_eval_num_neighbor_range_samples, 1001, "");
DEFINE_int32(param_opt_max_iterations, 5, "");

DEFINE_double(param_min_sample_point_confidence, 0.7, "");
DEFINE_double(param_min_num_confidence_tol_sample_points, 0.5, "");
DEFINE_double(param_min_cuboid_bbox_size, 0.1, "");
DEFINE_double(param_min_cuboid_bbox_diag_length, 0.3, "");
DEFINE_double(param_sparse_neighbor_distance, 0.05, "");
DEFINE_double(param_cuboid_split_neighbor_distance, 0.2, "");
DEFINE_double(param_occlusion_test_neighbor_distance, 0.01, "");
DEFINE_double(param_eval_max_neighbor_distance, 0.005, "");
DEFINE_double(param_min_cuboid_overall_visibility, 0.8, "");
DEFINE_double(param_max_potential, 1.0E8, "");
DEFINE_double(param_dummy_potential, 1.0E4, "");
DEFINE_double(param_opt_single_energy_term_weight, 1.0E4, "");
DEFINE_double(param_opt_symmetry_energy_term_weight, 1.0E6, "");
DEFINE_double(param_part_assembly_window_size, 0.1, "");
DEFINE_double(param_part_assembly_voxel_size, 0.01, "");
DEFINE_double(param_part_assembly_voxel_variance, 0.01, "");

//DEFINE_double(param_sim_abs_attr_tol, 0.2, "");
//DEFINE_double(param_zero_tol, 1.0E-6, "");
//
// ---- //

// -- Experiments -- //
//
DEFINE_bool(run_training, false, "");
DEFINE_bool(run_prediction, false, "");
DEFINE_bool(run_part_assembly, false, "");
DEFINE_string(mesh_filename, "", "");

DEFINE_string(data_root_path, "D:/Data/shape2pose/", "");
DEFINE_string(label_info_path, "data/0_body/assembly_chairs/", "");
DEFINE_string(mesh_path, "data/1_input/assembly_chairs/off/", "");
DEFINE_string(sample_path, "data/2_analysis/assembly_chairs/points/even1000/", "");
DEFINE_string(dense_sample_path, "data/2_analysis/assembly_chairs/points/random100000/", "");
DEFINE_string(mesh_label_path, "data/1_input/assembly_chairs/gt/", "");
DEFINE_string(sample_label_path, "data/4_experiments/exp1_assembly_chairs/1_prediction/", "");
DEFINE_string(output_dir, "output", "");
DEFINE_string(training_dir, "training", "");
DEFINE_string(part_assembly_dir, "part_assembly", "");

DEFINE_string(label_info_filename, "regions.txt", "");
DEFINE_string(label_symmetry_info_filename, "regions_symmetry.txt", "");
DEFINE_string(symmetry_group_info_filename, "symmetry_groups.txt", "");
DEFINE_string(pose_filename, "pose.txt", "");
DEFINE_string(occlusion_pose_filename, "", "");
//DEFINE_string(occlusion_pose_filename, "occlusion_pose.txt", "");

DEFINE_string(single_feature_filename_prefix, "single_feature_", "");
DEFINE_string(pair_feature_filename_prefix, "pair_feature_", "");
DEFINE_string(single_stats_filename_prefix, "single_stats_", "");
DEFINE_string(pair_stats_filename_prefix, "pair_stats_", "");
DEFINE_string(feature_filename_prefix, "feature_", "");
DEFINE_string(transformation_filename_prefix, "transformation_", "");
DEFINE_string(joint_normal_relation_filename_prefix, "joint_normal_", "");
DEFINE_string(cond_normal_relation_filename_prefix, "conditional_normal_", "");
DEFINE_string(object_list_filename, "object_list.txt", "");

DEFINE_double(occlusion_test_radius, 0.01, "");
DEFINE_int32(random_view_seed, 20150416, "");

// To be removed.
//DEFINE_bool(use_symmetric_group_cuboids, false, "");
//
// ---- //<commit_msg>Minor updates.<commit_after>#include "MeshCuboidParameters.h"

// -- Parameters -- //
//
DEFINE_bool(param_optimize_with_non_linear_constraints, true, "");
DEFINE_bool(param_optimize_training_cuboids, true, "");

DEFINE_int32(param_num_sample_point_neighbors, 8, "");
DEFINE_int32(param_min_num_cuboid_sample_points, 10, "");
DEFINE_int32(param_min_num_symmetric_point_pairs, 50, "");
DEFINE_int32(param_num_cuboid_surface_points, 1000, "");
DEFINE_int32(param_intra_cuboid_symmetry_axis, 0, "");
DEFINE_int32(param_eval_num_neighbor_range_samples, 1001, "");
DEFINE_int32(param_opt_max_iterations, 5, "");

DEFINE_double(param_min_sample_point_confidence, 0.7, "");
DEFINE_double(param_min_num_confidence_tol_sample_points, 0.5, "");
DEFINE_double(param_min_cuboid_bbox_size, 0.1, "");
DEFINE_double(param_min_cuboid_bbox_diag_length, 0.3, "");
DEFINE_double(param_sparse_neighbor_distance, 0.05, "");
DEFINE_double(param_cuboid_split_neighbor_distance, 0.2, "");
DEFINE_double(param_occlusion_test_neighbor_distance, 0.01, "");
DEFINE_double(param_eval_max_neighbor_distance, 0.1, "");
DEFINE_double(param_min_cuboid_overall_visibility, 0.8, "");
DEFINE_double(param_max_potential, 1.0E8, "");
DEFINE_double(param_dummy_potential, 1.0E4, "");
DEFINE_double(param_opt_single_energy_term_weight, 1.0E4, "");
DEFINE_double(param_opt_symmetry_energy_term_weight, 1.0E6, "");
DEFINE_double(param_part_assembly_window_size, 0.1, "");
DEFINE_double(param_part_assembly_voxel_size, 0.01, "");
DEFINE_double(param_part_assembly_voxel_variance, 0.01, "");

//DEFINE_double(param_sim_abs_attr_tol, 0.2, "");
//DEFINE_double(param_zero_tol, 1.0E-6, "");
//
// ---- //

// -- Experiments -- //
//
DEFINE_bool(run_training, false, "");
DEFINE_bool(run_prediction, false, "");
DEFINE_bool(run_part_assembly, false, "");
DEFINE_string(mesh_filename, "", "");

DEFINE_string(data_root_path, "D:/Data/shape2pose/", "");
DEFINE_string(label_info_path, "data/0_body/assembly_chairs/", "");
DEFINE_string(mesh_path, "data/1_input/assembly_chairs/off/", "");
DEFINE_string(sample_path, "data/2_analysis/assembly_chairs/points/even1000/", "");
DEFINE_string(dense_sample_path, "data/2_analysis/assembly_chairs/points/random100000/", "");
DEFINE_string(mesh_label_path, "data/1_input/assembly_chairs/gt/", "");
DEFINE_string(sample_label_path, "data/4_experiments/exp1_assembly_chairs/1_prediction/", "");
DEFINE_string(output_dir, "output", "");
DEFINE_string(training_dir, "training", "");
DEFINE_string(part_assembly_dir, "part_assembly", "");

DEFINE_string(label_info_filename, "regions.txt", "");
DEFINE_string(label_symmetry_info_filename, "regions_symmetry.txt", "");
DEFINE_string(symmetry_group_info_filename, "symmetry_groups.txt", "");
DEFINE_string(pose_filename, "pose.txt", "");
DEFINE_string(occlusion_pose_filename, "", "");
//DEFINE_string(occlusion_pose_filename, "occlusion_pose.txt", "");

DEFINE_string(single_feature_filename_prefix, "single_feature_", "");
DEFINE_string(pair_feature_filename_prefix, "pair_feature_", "");
DEFINE_string(single_stats_filename_prefix, "single_stats_", "");
DEFINE_string(pair_stats_filename_prefix, "pair_stats_", "");
DEFINE_string(feature_filename_prefix, "feature_", "");
DEFINE_string(transformation_filename_prefix, "transformation_", "");
DEFINE_string(joint_normal_relation_filename_prefix, "joint_normal_", "");
DEFINE_string(cond_normal_relation_filename_prefix, "conditional_normal_", "");
DEFINE_string(object_list_filename, "object_list.txt", "");

DEFINE_double(occlusion_test_radius, 0.01, "");
DEFINE_int32(random_view_seed, 20150416, "");

// To be removed.
//DEFINE_bool(use_symmetric_group_cuboids, false, "");
//
// ---- //<|endoftext|>


<commit_before>#include <algorithm>
#include <cstdio>
#include <limits>

#include "graphics.h"
#include "nesterovBase.h"
#include "placerBase.h"

namespace replace {

Graphics::Graphics(std::shared_ptr<PlacerBase> pb,
                   std::shared_ptr<NesterovBase> nb,
                   bool draw_bins)
    : pb_(pb), nb_(nb), selected_(nullptr), draw_bins_(draw_bins)
{
  gui::Gui::get()->register_renderer(this);
}

void Graphics::drawObjects(gui::Painter& painter)
{
  // draw core bounds
  auto& die = pb_->die();
  painter.setPen(gui::Painter::yellow, /* cosmetic */ true);
  painter.drawLine(die.coreLx(), die.coreLy(), die.coreUx(), die.coreLy());
  painter.drawLine(die.coreUx(), die.coreLy(), die.coreUx(), die.coreUy());
  painter.drawLine(die.coreUx(), die.coreUy(), die.coreLx(), die.coreUy());
  painter.drawLine(die.coreLx(), die.coreUy(), die.coreLx(), die.coreLy());

  if (draw_bins_) {
    // Draw the bins
    painter.setPen(gui::Painter::white, /* cosmetic */ true);
    for (auto& bin : nb_->bins()) {
      int color = bin->density() * 50 + 20;

      color = (color > 255) ? 255 : (color < 20) ? 20 : color;
      color = 255 - color;

      painter.setBrush({color, color, color, 180});
      painter.drawRect({bin->lx(), bin->ly(), bin->ux(), bin->uy()});
    }
  }

  // Draw the placeable objects
  painter.setPen(gui::Painter::white);
  for (auto* gCell : nb_->gCells()) {
    const int gcx = gCell->dCx();
    const int gcy = gCell->dCy();

    int xl = gcx - gCell->dx() / 2;
    int yl = gcy - gCell->dy() / 2;
    int xh = gcx + gCell->dx() / 2;
    int yh = gcy + gCell->dy() / 2;

    gui::Painter::Color color;
    if (gCell->isInstance()) {
      color = gui::Painter::dark_blue;
    } else if (gCell->isFiller()) {
      color = gui::Painter::dark_magenta;
    }
    if (gCell == selected_) {
      color = gui::Painter::yellow;
    }

    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({xl, yl, xh, yh});
  }

  // Draw lines to neighbors
  if (selected_) {
    painter.setPen(gui::Painter::yellow, true);
    for (GPin* pin : selected_->gPins()) {
      GNet* net = pin->gNet();
      if (!net) {
        continue;
      }
      for (GPin* other_pin : net->gPins()) {
        GCell* neighbor = other_pin->gCell();
        if (neighbor == selected_) {
          continue;
        }
        painter.drawLine(
            pin->cx(), pin->cy(), other_pin->cx(), other_pin->cy());
      }
    }
  }

  // Draw force direction lines
  if (draw_bins_) {
    float efMax = 0;
    int max_len = std::numeric_limits<int>::max();
    for (auto& bin : nb_->bins()) {
      efMax
          = std::max(efMax, hypot(bin->electroForceX(), bin->electroForceY()));
      max_len = std::min({max_len, bin->dx(), bin->dy()});
    }

    for (auto& bin : nb_->bins()) {
      float fx = bin->electroForceX();
      float fy = bin->electroForceY();
      float angle = atan(fy / fx);
      float ratio = hypot(fx, fy) / efMax;
      float dx = cos(angle) * max_len * ratio;
      float dy = sin(angle) * max_len * ratio;

      int cx = bin->cx();
      int cy = bin->cy();

      painter.setPen(gui::Painter::red, true);
      painter.drawLine(cx, cy, cx + dx, cy + dy);
    }
  }
}

void Graphics::cellPlot(bool pause)
{
  gui::Gui::get()->redraw();
  if (pause) {
    gui::Gui::get()->pause();
  }
}

gui::Selected Graphics::select(odb::dbTechLayer* layer, const odb::Point& point)
{
  selected_ = nullptr;

  if (layer) {
    return gui::Selected();
  }

  for (GCell* cell : nb_->gCells()) {
    const int gcx = cell->dCx();
    const int gcy = cell->dCy();

    int xl = gcx - cell->dx() / 2;
    int yl = gcy - cell->dy() / 2;
    int xh = gcx + cell->dx() / 2;
    int yh = gcy + cell->dy() / 2;

    if (point.x() < xl || point.y() < yl || point.x() > xh || point.y() > yh) {
      continue;
    }

    selected_ = cell;
    if (cell->isInstance()) {
      return gui::Selected(cell->instance()->dbInst());
    }
  }
  return gui::Selected();
}

void Graphics::status(const std::string& message)
{
  gui::Gui::get()->status(message);
}

/* static */
bool Graphics::guiActive()
{
  return gui::Gui::get() != nullptr;
}

}  // namespace replace
<commit_msg>replace: fix force line<commit_after>#include <algorithm>
#include <cstdio>
#include <limits>

#include "graphics.h"
#include "nesterovBase.h"
#include "placerBase.h"

namespace replace {

Graphics::Graphics(std::shared_ptr<PlacerBase> pb,
                   std::shared_ptr<NesterovBase> nb,
                   bool draw_bins)
    : pb_(pb), nb_(nb), selected_(nullptr), draw_bins_(draw_bins)
{
  gui::Gui::get()->register_renderer(this);
}

void Graphics::drawObjects(gui::Painter& painter)
{
  // draw core bounds
  auto& die = pb_->die();
  painter.setPen(gui::Painter::yellow, /* cosmetic */ true);
  painter.drawLine(die.coreLx(), die.coreLy(), die.coreUx(), die.coreLy());
  painter.drawLine(die.coreUx(), die.coreLy(), die.coreUx(), die.coreUy());
  painter.drawLine(die.coreUx(), die.coreUy(), die.coreLx(), die.coreUy());
  painter.drawLine(die.coreLx(), die.coreUy(), die.coreLx(), die.coreLy());

  if (draw_bins_) {
    // Draw the bins
    painter.setPen(gui::Painter::white, /* cosmetic */ true);
    for (auto& bin : nb_->bins()) {
      int color = bin->density() * 50 + 20;

      color = (color > 255) ? 255 : (color < 20) ? 20 : color;
      color = 255 - color;

      painter.setBrush({color, color, color, 180});
      painter.drawRect({bin->lx(), bin->ly(), bin->ux(), bin->uy()});
    }
  }

  // Draw the placeable objects
  painter.setPen(gui::Painter::white);
  for (auto* gCell : nb_->gCells()) {
    const int gcx = gCell->dCx();
    const int gcy = gCell->dCy();

    int xl = gcx - gCell->dx() / 2;
    int yl = gcy - gCell->dy() / 2;
    int xh = gcx + gCell->dx() / 2;
    int yh = gcy + gCell->dy() / 2;

    gui::Painter::Color color;
    if (gCell->isInstance()) {
      color = gui::Painter::dark_blue;
    } else if (gCell->isFiller()) {
      color = gui::Painter::dark_magenta;
    }
    if (gCell == selected_) {
      color = gui::Painter::yellow;
    }

    color.a = 180;
    painter.setBrush(color);
    painter.drawRect({xl, yl, xh, yh});
  }

  // Draw lines to neighbors
  if (selected_) {
    painter.setPen(gui::Painter::yellow, true);
    for (GPin* pin : selected_->gPins()) {
      GNet* net = pin->gNet();
      if (!net) {
        continue;
      }
      for (GPin* other_pin : net->gPins()) {
        GCell* neighbor = other_pin->gCell();
        if (neighbor == selected_) {
          continue;
        }
        painter.drawLine(
            pin->cx(), pin->cy(), other_pin->cx(), other_pin->cy());
      }
    }
  }

  // Draw force direction lines
  if (draw_bins_) {
    float efMax = 0;
    int max_len = std::numeric_limits<int>::max();
    for (auto& bin : nb_->bins()) {
      efMax
          = std::max(efMax, hypot(bin->electroForceX(), bin->electroForceY()));
      max_len = std::min({max_len, bin->dx(), bin->dy()});
    }

    for (auto& bin : nb_->bins()) {
      float fx = bin->electroForceX();
      float fy = bin->electroForceY();
      float f = hypot(fx, fy);
      float ratio = f / efMax;
      float dx = fx / f * max_len * ratio;
      float dy = fy / f * max_len * ratio;

      int cx = bin->cx();
      int cy = bin->cy();

      painter.setPen(gui::Painter::red, true);
      painter.drawLine(cx, cy, cx + dx, cy + dy);
    }
  }
}

void Graphics::cellPlot(bool pause)
{
  gui::Gui::get()->redraw();
  if (pause) {
    gui::Gui::get()->pause();
  }
}

gui::Selected Graphics::select(odb::dbTechLayer* layer, const odb::Point& point)
{
  selected_ = nullptr;

  if (layer) {
    return gui::Selected();
  }

  for (GCell* cell : nb_->gCells()) {
    const int gcx = cell->dCx();
    const int gcy = cell->dCy();

    int xl = gcx - cell->dx() / 2;
    int yl = gcy - cell->dy() / 2;
    int xh = gcx + cell->dx() / 2;
    int yh = gcy + cell->dy() / 2;

    if (point.x() < xl || point.y() < yl || point.x() > xh || point.y() > yh) {
      continue;
    }

    selected_ = cell;
    if (cell->isInstance()) {
      return gui::Selected(cell->instance()->dbInst());
    }
  }
  return gui::Selected();
}

void Graphics::status(const std::string& message)
{
  gui::Gui::get()->status(message);
}

/* static */
bool Graphics::guiActive()
{
  return gui::Gui::get() != nullptr;
}

}  // namespace replace
<|endoftext|>


<commit_before>#include "TextureFont.hpp"

using namespace rffalcon;

#define POINT_RES 64
#define DPI 72

TextureFont::TextureFont(std::shared_ptr<TextureAtlas> atlas, const float pointSize, const std::string &filename)
	: _atlas(atlas), _pointSize(pointSize), _filename(filename)
{
	_initialize();
}

TextureFont::~TextureFont()
{
}

float TextureFont::getHeight() const
{
	return _height;
}

void TextureFont::loadGlyphs(const std::string &text)
{
	int width = _atlas->getWidth();
	int height = _atlas->getHeight();
	int depth = _atlas->getDepth();

	FT_Library library;
	FT_Face face;
	_loadFace(&library, &face);
	int length = text.length();
	// Load the glyph for each character in the string
	for (int i = 0; i < length; ++i)
	{
		// Skip glyphs that have already been loaded
		for (int j = 0; j < _glyphs.size(); ++j)
		{
			TextureGlyph glyph = _glyphs[j];
			if (glyph.charCode == text[i])
			{

			}
		}
	}
}

void TextureFont::_initialize()
{
	FT_Library library;
	FT_Face face;
	FT_Size_Metrics metrics;

	FT_Error error = FT_Init_FreeType(&library);
	if (error != FT_Err_Ok)
	{
		throw new std::exception();
	}

	_loadFace(&library, &face, _pointSize * 100.0f);
	metrics = face->size->metrics;
	_ascender = (metrics.ascender >> 6) / 100.0f;
	_descender = (metrics.descender >> 6) / 100.0f;
	_height = (metrics.height >> 6) / 100.0f;
	_linegap = _height - _ascender + _descender;

	FT_Done_Face(face);
	FT_Done_FreeType(library);
}

void TextureFont::_loadFace(FT_Library *library, FT_Face *face, float pointSize)
{
	FT_Error error = FT_New_Face(*library, _filename.c_str(), 0, face);
	if (error != FT_Err_Ok)
	{
		throw new std::exception();
	}

	error = FT_Select_Charmap(*face, FT_ENCODING_UNICODE);
	if (error)
	{
		throw new std::exception();
	}

	error = FT_Set_Char_Size(*face, (int)(pointSize * POINT_RES), 0, DPI * POINT_RES, DPI);
	if (error)
	{
		throw new std::exception();
	}

	FT_Matrix matrix = {
		(int)((1.0 / POINT_RES) * 0x10000L),
		0,
		0,
		0x10000L
	};

	FT_Set_Transform(*face, &matrix, nullptr);
}

void TextureFont::_loadFace(FT_Library *library, FT_Face *face)
{
	_loadFace(library, face, _pointSize);
}<commit_msg>static_cast of size of glyphs to answer warning<commit_after>#include "TextureFont.hpp"

using namespace rffalcon;

#define POINT_RES 64
#define DPI 72

TextureFont::TextureFont(std::shared_ptr<TextureAtlas> atlas, const float pointSize, const std::string &filename)
	: _atlas(atlas), _pointSize(pointSize), _filename(filename)
{
	_initialize();
}

TextureFont::~TextureFont()
{
}

float TextureFont::getHeight() const
{
	return _height;
}

void TextureFont::loadGlyphs(const std::string &text)
{
	int width = _atlas->getWidth();
	int height = _atlas->getHeight();
	int depth = _atlas->getDepth();

	FT_Library library;
	FT_Face face;
	_loadFace(&library, &face);
	int length = text.length();
	int sizeGlyphs = static_cast<int>(_glyphs.size());
	// Load the glyph for each character in the string
	for (int i = 0; i < length; ++i)
	{
		// Skip glyphs that have already been loaded
		for (int j = 0; j < sizeGlyphs; ++j)
		{
			TextureGlyph glyph = _glyphs[j];
			if (glyph.charCode == text[i])
			{

			}
		}
	}
}

void TextureFont::_initialize()
{
	FT_Library library;
	FT_Face face;
	FT_Size_Metrics metrics;

	FT_Error error = FT_Init_FreeType(&library);
	if (error != FT_Err_Ok)
	{
		throw new std::exception();
	}

	_loadFace(&library, &face, _pointSize * 100.0f);
	metrics = face->size->metrics;
	_ascender = (metrics.ascender >> 6) / 100.0f;
	_descender = (metrics.descender >> 6) / 100.0f;
	_height = (metrics.height >> 6) / 100.0f;
	_linegap = _height - _ascender + _descender;

	FT_Done_Face(face);
	FT_Done_FreeType(library);
}

void TextureFont::_loadFace(FT_Library *library, FT_Face *face, float pointSize)
{
	FT_Error error = FT_New_Face(*library, _filename.c_str(), 0, face);
	if (error != FT_Err_Ok)
	{
		throw new std::exception();
	}

	error = FT_Select_Charmap(*face, FT_ENCODING_UNICODE);
	if (error)
	{
		throw new std::exception();
	}

	error = FT_Set_Char_Size(*face, (int)(pointSize * POINT_RES), 0, DPI * POINT_RES, DPI);
	if (error)
	{
		throw new std::exception();
	}

	FT_Matrix matrix = {
		(int)((1.0 / POINT_RES) * 0x10000L),
		0,
		0,
		0x10000L
	};

	FT_Set_Transform(*face, &matrix, nullptr);
}

void TextureFont::_loadFace(FT_Library *library, FT_Face *face)
{
	_loadFace(library, face, _pointSize);
}<|endoftext|>


<commit_before><commit_msg>typo - fixed reloading<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Buffer.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/SoftwareBuffer.hpp>
#include <memory>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	Buffer::Buffer(BufferType type) :
	m_type(type),
	m_usage(0),
	m_size(0)
	{
	}

	Buffer::Buffer(BufferType type, UInt32 size, DataStorage storage, BufferUsageFlags usage) :
	Buffer(type)
	{
		ErrorFlags flags(ErrorFlag_ThrowException, true);

		Create(size, storage, usage);
	}

	Buffer::~Buffer()
	{
		OnBufferRelease(this);

		Destroy();
	}

	bool Buffer::CopyContent(const BufferRef& buffer)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(!buffer && !buffer->IsValid(), "Invalid source buffer");

		BufferMapper<Buffer> mapper(*buffer, BufferAccess_ReadOnly);
		return Fill(mapper.GetPointer(), 0, buffer->GetSize());
	}

	bool Buffer::Create(UInt32 size, DataStorage storage, BufferUsageFlags usage)
	{
		Destroy();

		// Notre buffer est-il supporté ?
		if (!IsStorageSupported(storage))
		{
			NazaraError("Buffer storage not supported");
			return false;
		}

		std::unique_ptr<AbstractBuffer> impl(s_bufferFactories[storage](this, m_type));
		if (!impl->Initialize(size, usage))
		{
			NazaraError("Failed to create buffer");
			return false;
		}

		m_impl = std::move(impl);
		m_size = size;
		m_usage = usage;

		return true; // Si on arrive ici c'est que tout s'est bien passé.
	}

	void Buffer::Destroy()
	{
		if (!m_impl)
		{
			OnBufferDestroy(this);

			m_impl.reset();
		}
	}

	bool Buffer::Fill(const void* data, UInt32 offset, UInt32 size)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Fill(data, offset, (size == 0) ? m_size - offset : size);
	}

	void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size);
	}

	void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size) const
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(access == BufferAccess_ReadOnly, "Buffer access must be read-only when used const");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size);
	}

	bool Buffer::SetStorage(DataStorage storage)
	{
		NazaraAssert(m_impl, "Invalid buffer");

		if (HasStorage(storage))
			return true;

		if (!IsStorageSupported(storage))
		{
			NazaraError("Storage not supported");
			return false;
		}

		void* ptr = m_impl->Map(BufferAccess_ReadOnly, 0, m_size);
		if (!ptr)
		{
			NazaraError("Failed to map buffer");
			return false;
		}

		CallOnExit unmapMyImpl([this]()
		{
			m_impl->Unmap();
		});

		std::unique_ptr<AbstractBuffer> impl(s_bufferFactories[storage](this, m_type));
		if (!impl->Initialize(m_size, m_usage))
		{
			NazaraError("Failed to create buffer");
			return false;
		}

		if (!impl->Fill(ptr, 0, m_size))
		{
			NazaraError("Failed to fill buffer");
			return false;
		}

		unmapMyImpl.CallAndReset();

		m_impl = std::move(impl);

		return true;
	}

	void Buffer::Unmap() const
	{
		NazaraAssert(m_impl, "Invalid buffer");

		if (!m_impl->Unmap())
			NazaraWarning("Failed to unmap buffer (it's content may be undefined)"); ///TODO: Unexpected ?
	}

	bool Buffer::IsStorageSupported(DataStorage storage)
	{
		return s_bufferFactories[storage] != nullptr;
	}

	void Buffer::SetBufferFactory(DataStorage storage, BufferFactory func)
	{
		s_bufferFactories[storage] = func;
	}

	bool Buffer::Initialize()
	{
		SetBufferFactory(DataStorage_Software, [](Buffer* parent, BufferType type) -> AbstractBuffer*
		{
			return new SoftwareBuffer(parent, type);
		});

		return true;
	}

	void Buffer::Uninitialize()
	{
		std::fill(s_bufferFactories.begin(), s_bufferFactories.end(), nullptr);
	}

	std::array<Buffer::BufferFactory, DataStorage_Max + 1> Buffer::s_bufferFactories;
}
<commit_msg>Utility/Buffer: Fix Destroy() not really destroying buffer<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Buffer.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/SoftwareBuffer.hpp>
#include <memory>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	Buffer::Buffer(BufferType type) :
	m_type(type),
	m_usage(0),
	m_size(0)
	{
	}

	Buffer::Buffer(BufferType type, UInt32 size, DataStorage storage, BufferUsageFlags usage) :
	Buffer(type)
	{
		ErrorFlags flags(ErrorFlag_ThrowException, true);

		Create(size, storage, usage);
	}

	Buffer::~Buffer()
	{
		OnBufferRelease(this);

		Destroy();
	}

	bool Buffer::CopyContent(const BufferRef& buffer)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(!buffer && !buffer->IsValid(), "Invalid source buffer");

		BufferMapper<Buffer> mapper(*buffer, BufferAccess_ReadOnly);
		return Fill(mapper.GetPointer(), 0, buffer->GetSize());
	}

	bool Buffer::Create(UInt32 size, DataStorage storage, BufferUsageFlags usage)
	{
		Destroy();

		// Notre buffer est-il supporté ?
		if (!IsStorageSupported(storage))
		{
			NazaraError("Buffer storage not supported");
			return false;
		}

		std::unique_ptr<AbstractBuffer> impl(s_bufferFactories[storage](this, m_type));
		if (!impl->Initialize(size, usage))
		{
			NazaraError("Failed to create buffer");
			return false;
		}

		m_impl = std::move(impl);
		m_size = size;
		m_usage = usage;

		return true; // Si on arrive ici c'est que tout s'est bien passé.
	}

	void Buffer::Destroy()
	{
		if (m_impl)
		{
			OnBufferDestroy(this);

			m_impl.reset();
		}
	}

	bool Buffer::Fill(const void* data, UInt32 offset, UInt32 size)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Fill(data, offset, (size == 0) ? m_size - offset : size);
	}

	void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size)
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size);
	}

	void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size) const
	{
		NazaraAssert(m_impl, "Invalid buffer");
		NazaraAssert(access == BufferAccess_ReadOnly, "Buffer access must be read-only when used const");
		NazaraAssert(offset + size <= m_size, "Exceeding buffer size");

		return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size);
	}

	bool Buffer::SetStorage(DataStorage storage)
	{
		NazaraAssert(m_impl, "Invalid buffer");

		if (HasStorage(storage))
			return true;

		if (!IsStorageSupported(storage))
		{
			NazaraError("Storage not supported");
			return false;
		}

		void* ptr = m_impl->Map(BufferAccess_ReadOnly, 0, m_size);
		if (!ptr)
		{
			NazaraError("Failed to map buffer");
			return false;
		}

		CallOnExit unmapMyImpl([this]()
		{
			m_impl->Unmap();
		});

		std::unique_ptr<AbstractBuffer> impl(s_bufferFactories[storage](this, m_type));
		if (!impl->Initialize(m_size, m_usage))
		{
			NazaraError("Failed to create buffer");
			return false;
		}

		if (!impl->Fill(ptr, 0, m_size))
		{
			NazaraError("Failed to fill buffer");
			return false;
		}

		unmapMyImpl.CallAndReset();

		m_impl = std::move(impl);

		return true;
	}

	void Buffer::Unmap() const
	{
		NazaraAssert(m_impl, "Invalid buffer");

		if (!m_impl->Unmap())
			NazaraWarning("Failed to unmap buffer (it's content may be undefined)"); ///TODO: Unexpected ?
	}

	bool Buffer::IsStorageSupported(DataStorage storage)
	{
		return s_bufferFactories[storage] != nullptr;
	}

	void Buffer::SetBufferFactory(DataStorage storage, BufferFactory func)
	{
		s_bufferFactories[storage] = func;
	}

	bool Buffer::Initialize()
	{
		SetBufferFactory(DataStorage_Software, [](Buffer* parent, BufferType type) -> AbstractBuffer*
		{
			return new SoftwareBuffer(parent, type);
		});

		return true;
	}

	void Buffer::Uninitialize()
	{
		std::fill(s_bufferFactories.begin(), s_bufferFactories.end(), nullptr);
	}

	std::array<Buffer::BufferFactory, DataStorage_Max + 1> Buffer::s_bufferFactories;
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <zmq.hpp>

#if defined(ZMQ_CPP11) && defined(ZMQ_BUILD_DRAFT_API)

#include <array>
#include <memory>

TEST(poller, create_destroy)
{
    zmq::poller_t poller;
    ASSERT_EQ(0u, poller.size ());
}

static_assert(!std::is_copy_constructible<zmq::poller_t>::value, "poller_t should not be copy-constructible");
static_assert(!std::is_copy_assignable<zmq::poller_t>::value, "poller_t should not be copy-assignable");

TEST(poller, move_construct_empty)
{
    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    zmq::poller_t b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_assign_empty)
{
    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    zmq::poller_t b;

    b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_construct_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};

    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    a->add(socket, ZMQ_POLLIN, [](short) {});
    zmq::poller_t b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(1u, b.size ());
}

TEST(poller, move_assign_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};

    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    a->add(socket, ZMQ_POLLIN, [](short) {});
    zmq::poller_t b;

    b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(1u, b.size ());
}

TEST(poller, add_handler)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    ASSERT_NO_THROW(poller.add(socket, ZMQ_POLLIN, handler));
}

TEST(poller, add_handler_invalid_events_type)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    short invalid_events_type = 2 << 10;
    ASSERT_NO_THROW(poller.add(socket, invalid_events_type, handler));
}

TEST(poller, add_handler_twice_throws)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    poller.add(socket, ZMQ_POLLIN, handler);
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.add(socket, ZMQ_POLLIN, handler), zmq::error_t);
}

TEST(poller, wait_with_no_handlers_throws)
{
    zmq::poller_t poller;
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.wait(std::chrono::milliseconds{10}), zmq::error_t);
}

TEST(poller, remove_unregistered_throws)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.remove(socket), zmq::error_t);
}

TEST(poller, remove_registered_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    poller.add(socket, ZMQ_POLLIN, zmq::poller_t::handler_t{});
    ASSERT_NO_THROW(poller.remove(socket));
}

TEST(poller, remove_registered_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    poller.add(socket, ZMQ_POLLIN, [](short) {});
    ASSERT_NO_THROW(poller.remove(socket));
}

namespace {

class loopback_ip4_binder
{
public:
    loopback_ip4_binder(zmq::socket_t &socket) { bind(socket); }
    std::string endpoint() { return endpoint_; }
private:
    // Helper function used in constructor
    // as Gtest allows ASSERT_* only in void returning functions
    // and constructor/destructor are not.
    void bind(zmq::socket_t &socket)
    {
        ASSERT_NO_THROW(socket.bind("tcp://127.0.0.1:*"));
        std::array<char, 100> endpoint{};
        size_t endpoint_size = endpoint.size();
        ASSERT_NO_THROW(socket.getsockopt(ZMQ_LAST_ENDPOINT, endpoint.data(),
                                          &endpoint_size));
        ASSERT_TRUE(endpoint_size < endpoint.size());
        endpoint_ = std::string{endpoint.data()};
    }
    std::string endpoint_;
};

struct server_client_setup
{
    server_client_setup ()
    {
        init ();
    }

    void init()
    {
        endpoint = loopback_ip4_binder {server}.endpoint ();
        ASSERT_NO_THROW (client.connect (endpoint));
    }

    zmq::poller_t::handler_t handler = [&](short e) {
        events = e;
    };

    zmq::context_t context;
    zmq::socket_t server {context, zmq::socket_type::router};
    zmq::socket_t client {context, zmq::socket_type::dealer};
    std::string endpoint;
    short events = 0;
};

} //namespace

TEST(poller, poll_basic)
{
    server_client_setup s;

    ASSERT_NO_THROW(s.client.send("Hi"));

    zmq::poller_t poller;
    bool message_received = false;
    zmq::poller_t::handler_t handler = [&message_received](short events) {
        ASSERT_TRUE(0 != (events & ZMQ_POLLIN));
        message_received = true;
    };
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_TRUE(message_received);
}

/// \todo this contains multiple test cases that should be split up
TEST(poller, client_server)
{
    const std::string send_msg = "Hi";

    // Setup server and client
    server_client_setup s;

    // Setup poller
    zmq::poller_t poller;
    short events;
    zmq::poller_t::handler_t handler = [&](short e) {
        if (0 != (e & ZMQ_POLLIN)) {
            zmq::message_t zmq_msg;
            ASSERT_NO_THROW(s.server.recv(&zmq_msg)); // skip msg id
            ASSERT_NO_THROW(s.server.recv(&zmq_msg)); // get message
            std::string recv_msg(zmq_msg.data<char>(),
                                 zmq_msg.size());
            ASSERT_EQ(send_msg, recv_msg);
        } else if (0 != (e & ~ZMQ_POLLOUT)) {
            ASSERT_TRUE(false) << "Unexpected event type " << events;
        }
        events = e;
    };

    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));

    // client sends message
    ASSERT_NO_THROW(s.client.send(send_msg));

    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_EQ(events, ZMQ_POLLIN);

    // Re-add server socket with pollout flag
    ASSERT_NO_THROW(poller.remove(s.server));
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN | ZMQ_POLLOUT, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_EQ(events, ZMQ_POLLOUT);
}

TEST(poller, poller_add_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::poller_t poller;
    zmq::socket_t a {context, zmq::socket_type::router};
    zmq::socket_t b {std::move (a)};
    ASSERT_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}),
                  zmq::error_t);
    ASSERT_EQ (0u, poller.size ());
}

TEST(poller, poller_remove_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::socket_t socket {context, zmq::socket_type::router};
    zmq::poller_t poller;
    ASSERT_NO_THROW (poller.add (socket, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
    ASSERT_EQ (1u, poller.size ());
    std::vector<zmq::socket_t> sockets;
    sockets.emplace_back (std::move (socket));
    ASSERT_THROW (poller.remove (socket), zmq::error_t);
    ASSERT_EQ (1u, poller.size ());
}

TEST(poller, wait_on_added_empty_handler)
{
    server_client_setup s;
    ASSERT_NO_THROW(s.client.send("Hi"));
    zmq::poller_t poller;
    std::function<void(void)> handler;
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
}

TEST(poller, modify_empty_throws)
{
    zmq::context_t context;
    zmq::socket_t socket {context, zmq::socket_type::push};
    zmq::poller_t poller;
    ASSERT_THROW (poller.modify (socket, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, modify_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::socket_t a {context, zmq::socket_type::push};
    zmq::socket_t b {std::move (a)};
    zmq::poller_t poller;
    ASSERT_THROW (poller.modify (a, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, modified_not_added_throws)
{
    zmq::context_t context;
    zmq::socket_t a {context, zmq::socket_type::push};
    zmq::socket_t b {context, zmq::socket_type::push};
    zmq::poller_t poller;
    ASSERT_NO_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
    ASSERT_THROW (poller.modify (b, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, poll_client_server)
{
    // Setup server and client
    server_client_setup s;

    // Setup poller
    zmq::poller_t poller;
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, s.handler));

    // client sends message
    ASSERT_NO_THROW(s.client.send("Hi"));

    // wait for message and verify events
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{500}));
    ASSERT_TRUE(s.events == ZMQ_POLLIN);
    ASSERT_EQ(s.events, ZMQ_POLLIN);

    // Modify server socket with pollout flag
    ASSERT_NO_THROW(poller.modify(s.server, ZMQ_POLLIN | ZMQ_POLLOUT));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{500}));
    ASSERT_EQ(s.events, ZMQ_POLLIN | ZMQ_POLLOUT);
}

#endif
<commit_msg>Problem: poller_t simple modify test case missing<commit_after>#include <gtest/gtest.h>
#include <zmq.hpp>

#if defined(ZMQ_CPP11) && defined(ZMQ_BUILD_DRAFT_API)

#include <array>
#include <memory>

TEST(poller, create_destroy)
{
    zmq::poller_t poller;
    ASSERT_EQ(0u, poller.size ());
}

static_assert(!std::is_copy_constructible<zmq::poller_t>::value, "poller_t should not be copy-constructible");
static_assert(!std::is_copy_assignable<zmq::poller_t>::value, "poller_t should not be copy-assignable");

TEST(poller, move_construct_empty)
{
    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    zmq::poller_t b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_assign_empty)
{
    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    zmq::poller_t b;

    b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_construct_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};

    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    a->add(socket, ZMQ_POLLIN, [](short) {});
    zmq::poller_t b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(1u, b.size ());
}

TEST(poller, move_assign_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};

    std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
    a->add(socket, ZMQ_POLLIN, [](short) {});
    zmq::poller_t b;

    b = std::move(*a);

    ASSERT_EQ(0u, a->size ());
    a.reset ();
    ASSERT_EQ(1u, b.size ());
}

TEST(poller, add_handler)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    ASSERT_NO_THROW(poller.add(socket, ZMQ_POLLIN, handler));
}

TEST(poller, add_handler_invalid_events_type)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    short invalid_events_type = 2 << 10;
    ASSERT_NO_THROW(poller.add(socket, invalid_events_type, handler));
}

TEST(poller, add_handler_twice_throws)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    zmq::poller_t::handler_t handler;
    poller.add(socket, ZMQ_POLLIN, handler);
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.add(socket, ZMQ_POLLIN, handler), zmq::error_t);
}

TEST(poller, wait_with_no_handlers_throws)
{
    zmq::poller_t poller;
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.wait(std::chrono::milliseconds{10}), zmq::error_t);
}

TEST(poller, remove_unregistered_throws)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    /// \todo the actual error code should be checked
    ASSERT_THROW(poller.remove(socket), zmq::error_t);
}

TEST(poller, remove_registered_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    poller.add(socket, ZMQ_POLLIN, zmq::poller_t::handler_t{});
    ASSERT_NO_THROW(poller.remove(socket));
}

TEST(poller, remove_registered_non_empty)
{
    zmq::context_t context;
    zmq::socket_t socket{context, zmq::socket_type::router};
    zmq::poller_t poller;
    poller.add(socket, ZMQ_POLLIN, [](short) {});
    ASSERT_NO_THROW(poller.remove(socket));
}

namespace {

class loopback_ip4_binder
{
public:
    loopback_ip4_binder(zmq::socket_t &socket) { bind(socket); }
    std::string endpoint() { return endpoint_; }
private:
    // Helper function used in constructor
    // as Gtest allows ASSERT_* only in void returning functions
    // and constructor/destructor are not.
    void bind(zmq::socket_t &socket)
    {
        ASSERT_NO_THROW(socket.bind("tcp://127.0.0.1:*"));
        std::array<char, 100> endpoint{};
        size_t endpoint_size = endpoint.size();
        ASSERT_NO_THROW(socket.getsockopt(ZMQ_LAST_ENDPOINT, endpoint.data(),
                                          &endpoint_size));
        ASSERT_TRUE(endpoint_size < endpoint.size());
        endpoint_ = std::string{endpoint.data()};
    }
    std::string endpoint_;
};

struct server_client_setup
{
    server_client_setup ()
    {
        init ();
    }

    void init()
    {
        endpoint = loopback_ip4_binder {server}.endpoint ();
        ASSERT_NO_THROW (client.connect (endpoint));
    }

    zmq::poller_t::handler_t handler = [&](short e) {
        events = e;
    };

    zmq::context_t context;
    zmq::socket_t server {context, zmq::socket_type::router};
    zmq::socket_t client {context, zmq::socket_type::dealer};
    std::string endpoint;
    short events = 0;
};

} //namespace

TEST(poller, poll_basic)
{
    server_client_setup s;

    ASSERT_NO_THROW(s.client.send("Hi"));

    zmq::poller_t poller;
    bool message_received = false;
    zmq::poller_t::handler_t handler = [&message_received](short events) {
        ASSERT_TRUE(0 != (events & ZMQ_POLLIN));
        message_received = true;
    };
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_TRUE(message_received);
}

/// \todo this contains multiple test cases that should be split up
TEST(poller, client_server)
{
    const std::string send_msg = "Hi";

    // Setup server and client
    server_client_setup s;

    // Setup poller
    zmq::poller_t poller;
    short events;
    zmq::poller_t::handler_t handler = [&](short e) {
        if (0 != (e & ZMQ_POLLIN)) {
            zmq::message_t zmq_msg;
            ASSERT_NO_THROW(s.server.recv(&zmq_msg)); // skip msg id
            ASSERT_NO_THROW(s.server.recv(&zmq_msg)); // get message
            std::string recv_msg(zmq_msg.data<char>(),
                                 zmq_msg.size());
            ASSERT_EQ(send_msg, recv_msg);
        } else if (0 != (e & ~ZMQ_POLLOUT)) {
            ASSERT_TRUE(false) << "Unexpected event type " << events;
        }
        events = e;
    };

    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));

    // client sends message
    ASSERT_NO_THROW(s.client.send(send_msg));

    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_EQ(events, ZMQ_POLLIN);

    // Re-add server socket with pollout flag
    ASSERT_NO_THROW(poller.remove(s.server));
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN | ZMQ_POLLOUT, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
    ASSERT_EQ(events, ZMQ_POLLOUT);
}

TEST(poller, poller_add_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::poller_t poller;
    zmq::socket_t a {context, zmq::socket_type::router};
    zmq::socket_t b {std::move (a)};
    ASSERT_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}),
                  zmq::error_t);
    ASSERT_EQ (0u, poller.size ());
}

TEST(poller, poller_remove_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::socket_t socket {context, zmq::socket_type::router};
    zmq::poller_t poller;
    ASSERT_NO_THROW (poller.add (socket, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
    ASSERT_EQ (1u, poller.size ());
    std::vector<zmq::socket_t> sockets;
    sockets.emplace_back (std::move (socket));
    ASSERT_THROW (poller.remove (socket), zmq::error_t);
    ASSERT_EQ (1u, poller.size ());
}

TEST(poller, wait_on_added_empty_handler)
{
    server_client_setup s;
    ASSERT_NO_THROW(s.client.send("Hi"));
    zmq::poller_t poller;
    std::function<void(void)> handler;
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, handler));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
}

TEST(poller, modify_empty_throws)
{
    zmq::context_t context;
    zmq::socket_t socket {context, zmq::socket_type::push};
    zmq::poller_t poller;
    ASSERT_THROW (poller.modify (socket, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, modify_invalid_socket_throws)
{
    zmq::context_t context;
    zmq::socket_t a {context, zmq::socket_type::push};
    zmq::socket_t b {std::move (a)};
    zmq::poller_t poller;
    ASSERT_THROW (poller.modify (a, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, modify_not_added_throws)
{
    zmq::context_t context;
    zmq::socket_t a {context, zmq::socket_type::push};
    zmq::socket_t b {context, zmq::socket_type::push};
    zmq::poller_t poller;
    ASSERT_NO_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
    ASSERT_THROW (poller.modify (b, ZMQ_POLLIN), zmq::error_t);
}

TEST(poller, modify_simple)
{
    zmq::context_t context;
    zmq::socket_t a {context, zmq::socket_type::push};
    zmq::poller_t poller;
    ASSERT_NO_THROW (poller.add (a, ZMQ_POLLIN, zmq::poller_t::handler_t {}));
    ASSERT_NO_THROW (poller.modify (a, ZMQ_POLLIN|ZMQ_POLLOUT));
}

TEST(poller, poll_client_server)
{
    // Setup server and client
    server_client_setup s;

    // Setup poller
    zmq::poller_t poller;
    ASSERT_NO_THROW(poller.add(s.server, ZMQ_POLLIN, s.handler));

    // client sends message
    ASSERT_NO_THROW(s.client.send("Hi"));

    // wait for message and verify events
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{500}));
    ASSERT_TRUE(s.events == ZMQ_POLLIN);
    ASSERT_EQ(s.events, ZMQ_POLLIN);

    // Modify server socket with pollout flag
    ASSERT_NO_THROW(poller.modify(s.server, ZMQ_POLLIN | ZMQ_POLLOUT));
    ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{500}));
    ASSERT_EQ(s.events, ZMQ_POLLIN | ZMQ_POLLOUT);
}

#endif
<|endoftext|>