<commit_before>#include "Runtime/World/CScriptDamageableTrigger.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CScriptActor.hpp"
#include "Runtime/World/CWorld.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
static CActorParameters MakeDamageableTriggerActorParms(const CActorParameters& aParams, const CVisorParameters& vParams) {
  CActorParameters ret = aParams;
  ret.SetVisorParameters(vParams);
  return ret;
}

static constexpr CMaterialList MakeDamageableTriggerMaterial(CScriptDamageableTrigger::ECanOrbit canOrbit) {
  if (canOrbit == CScriptDamageableTrigger::ECanOrbit::Orbit) {
    return CMaterialList(EMaterialTypes::Orbit, EMaterialTypes::Trigger, EMaterialTypes::Immovable,
                         EMaterialTypes::NonSolidDamageable, EMaterialTypes::ExcludeFromLineOfSightTest);
  }
  return CMaterialList(EMaterialTypes::Trigger, EMaterialTypes::Immovable, EMaterialTypes::NonSolidDamageable,
                       EMaterialTypes::ExcludeFromLineOfSightTest);
}

CScriptDamageableTrigger::CScriptDamageableTrigger(TUniqueId uid, std::string_view name, const CEntityInfo& info,
                                                   const zeus::CVector3f& position, const zeus::CVector3f& extent,
                                                   const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
                                                   u32 faceFlag, CAssetId patternTex1, CAssetId patternTex2,
                                                   CAssetId colorTex, ECanOrbit canOrbit, bool active,
                                                   const CVisorParameters& vParams)
: CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(),
         MakeDamageableTriggerMaterial(canOrbit), MakeDamageableTriggerActorParms(CActorParameters::None(), vParams),
         kInvalidUniqueId)
, x14c_bounds(-extent * 0.5f, extent * 0.5f)
, x164_origHInfo(hInfo)
, x16c_hInfo(hInfo)
, x174_dVuln(dVuln)
, x1dc_faceFlag(faceFlag)
, x254_fluidPlane(patternTex1, patternTex2, colorTex, 1.f, 2, EFluidType::NormalWater, 1.f, CFluidUVMotion(6.f, 0.f))
, x300_28_canOrbit(canOrbit == ECanOrbit::Orbit) {
  if (x1dc_faceFlag & 0x1) {
    x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.max.y(), 0.f);
    x1e4_faceDir = zeus::CTransform::RotateX(-M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x2) {
    x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.min.y(), 0.f);
    x1e4_faceDir = zeus::CTransform::RotateX(M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x4) {
    x244_faceTranslate = zeus::CVector3f(x14c_bounds.min.x(), 0.f, 0.f);
    x1e4_faceDir = zeus::CTransform::RotateY(-M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x8) {
    x244_faceTranslate = zeus::CVector3f(x14c_bounds.max.x(), 0.f, 0.f);
    x1e4_faceDir = zeus::CTransform::RotateY(M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x10) {
    x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.max.z());
    x1e4_faceDir = zeus::CTransform();
  } else if (x1dc_faceFlag & 0x20) {
    x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.min.z());
    x1e4_faceDir = zeus::CTransform::RotateY(M_PIF);
  }

  x214_faceDirInv = x1e4_faceDir.inverse();
}

void CScriptDamageableTrigger::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptDamageableTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
  switch (msg) {
  case EScriptObjectMessage::Deactivate:
    if (x30_24_active && x300_25_alphaOut)
      return;
    [[fallthrough]];
  case EScriptObjectMessage::Activate:
    if (!x30_24_active || x300_25_alphaOut) {
      x250_alphaTimer = 0.f;
      x16c_hInfo = x164_origHInfo;
      x300_25_alphaOut = false;
      if (x300_28_canOrbit)
        AddMaterial(EMaterialTypes::Orbit, mgr);
      SetLinkedObjectAlpha(0.f, mgr);
      x1e0_alpha = 0.f;
    }
    break;
  case EScriptObjectMessage::Damage:
    if (x300_27_invulnerable)
      x16c_hInfo = x164_origHInfo;
    break;
  case EScriptObjectMessage::Increment:
    x300_27_invulnerable = true;
    break;
  case EScriptObjectMessage::Decrement:
    x300_27_invulnerable = false;
    break;
  default:
    break;
  }

  CActor::AcceptScriptMsg(msg, sender, mgr);
}

EWeaponCollisionResponseTypes CScriptDamageableTrigger::GetCollisionResponseType(const zeus::CVector3f&,
                                                                                const zeus::CVector3f&,
                                                                                const CWeaponMode& weapMode,
                                                                                EProjectileAttrib) const {
  return x174_dVuln.WeaponHurts(weapMode, false) ? EWeaponCollisionResponseTypes::OtherProjectile
                                                 : EWeaponCollisionResponseTypes::Unknown15;
}

void CScriptDamageableTrigger::Render(CStateManager& mgr) {
  if (x30_24_active && x1dc_faceFlag != 0 && std::fabs(x1e0_alpha) >= 0.00001f) {
    zeus::CAABox aabb = x14c_bounds.getTransformedAABox(x214_faceDirInv);
    zeus::CTransform xf = x34_transform * zeus::CTransform::Translate(x244_faceTranslate) * x1e4_faceDir;
    x254_fluidPlane.Render(mgr, x1e0_alpha, aabb, xf, zeus::CTransform(), false, xe8_frustum, {},
                           kInvalidUniqueId, nullptr, 0, 0, zeus::skZero3f);
  }

  CActor::Render(mgr);
}

void CScriptDamageableTrigger::AddToRenderer(const zeus::CFrustum& /*frustum*/, CStateManager& mgr) {
  if (x300_26_outOfFrustum) {
    return;
  }

  EnsureRendered(mgr, GetTranslation() - x244_faceTranslate, GetSortingBounds(mgr));
}

void CScriptDamageableTrigger::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
  x300_26_outOfFrustum = !frustum.aabbFrustumTest(x14c_bounds.getTransformedAABox(x34_transform));
  if (!x300_26_outOfFrustum) {
    xe8_frustum = frustum;
    CActor::PreRender(mgr, frustum);
  }
}

void CScriptDamageableTrigger::SetLinkedObjectAlpha(float a, CStateManager& mgr) {
  for (const SConnection& conn : x20_conns) {
    if (conn.x0_state != EScriptObjectState::MaxReached || conn.x4_msg != EScriptObjectMessage::Activate)
      continue;
    if (TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) {
      if (!act->GetActive())
        act->SetActive(true);
      act->SetDrawFlags(CModelFlags(5, 0, 3, zeus::CColor(1.f, a)));
    }
  }
}

float CScriptDamageableTrigger::GetPuddleAlphaScale() const {
  if (x250_alphaTimer <= 0.75f) {
    if (x300_25_alphaOut)
      return 1.f - x250_alphaTimer / 0.75f;
    return x250_alphaTimer / 0.75f;
  }

  if (x300_25_alphaOut)
    return 0.f;
  return 1.f;
}

void CScriptDamageableTrigger::Think(float dt, CStateManager& mgr) {
  if (!GetActive())
    return;

  const CGameArea* area = mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways());
  CGameArea::EOcclusionState occState =
      area->IsPostConstructed() ? area->GetOcclusionState() : CGameArea::EOcclusionState::Occluded;
  x300_24_notOccluded = occState == CGameArea::EOcclusionState::Visible;

  if (x300_25_alphaOut) {
    if (x250_alphaTimer >= 0.75f) {
      SetActive(false);
      for (const SConnection& conn : x20_conns) {
        if (conn.x0_state != EScriptObjectState::MaxReached || conn.x4_msg != EScriptObjectMessage::Activate)
          continue;
        if (TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId)))
          act->SetActive(false);
      }

      SetLinkedObjectAlpha(0.f, mgr);
      x300_25_alphaOut = false;
      return;
    }
  } else if (x16c_hInfo.GetHP() <= 0.f && x30_24_active) {
    SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None);
    RemoveMaterial(EMaterialTypes::Orbit, mgr);
    x300_25_alphaOut = true;
    x250_alphaTimer = 0.f;
  }

  if (x250_alphaTimer <= 0.75f)
    x250_alphaTimer += dt;

  float objAlpha = GetPuddleAlphaScale();
  x1e0_alpha = 0.2f * objAlpha;
  SetLinkedObjectAlpha(objAlpha, mgr);
}

std::optional<zeus::CAABox> CScriptDamageableTrigger::GetTouchBounds() const {
  if (x30_24_active && x300_24_notOccluded) {
    return zeus::CAABox(x14c_bounds.min + GetTranslation(), x14c_bounds.max + GetTranslation());
  }
  return std::nullopt;
}

} // namespace urde
<commit_msg>CScriptDamageableTrigger: Brace conditions where applicable<commit_after>#include "Runtime/World/CScriptDamageableTrigger.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CScriptActor.hpp"
#include "Runtime/World/CWorld.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
static CActorParameters MakeDamageableTriggerActorParms(const CActorParameters& aParams, const CVisorParameters& vParams) {
  CActorParameters ret = aParams;
  ret.SetVisorParameters(vParams);
  return ret;
}

static constexpr CMaterialList MakeDamageableTriggerMaterial(CScriptDamageableTrigger::ECanOrbit canOrbit) {
  if (canOrbit == CScriptDamageableTrigger::ECanOrbit::Orbit) {
    return CMaterialList(EMaterialTypes::Orbit, EMaterialTypes::Trigger, EMaterialTypes::Immovable,
                         EMaterialTypes::NonSolidDamageable, EMaterialTypes::ExcludeFromLineOfSightTest);
  }
  return CMaterialList(EMaterialTypes::Trigger, EMaterialTypes::Immovable, EMaterialTypes::NonSolidDamageable,
                       EMaterialTypes::ExcludeFromLineOfSightTest);
}

CScriptDamageableTrigger::CScriptDamageableTrigger(TUniqueId uid, std::string_view name, const CEntityInfo& info,
                                                   const zeus::CVector3f& position, const zeus::CVector3f& extent,
                                                   const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
                                                   u32 faceFlag, CAssetId patternTex1, CAssetId patternTex2,
                                                   CAssetId colorTex, ECanOrbit canOrbit, bool active,
                                                   const CVisorParameters& vParams)
: CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(),
         MakeDamageableTriggerMaterial(canOrbit), MakeDamageableTriggerActorParms(CActorParameters::None(), vParams),
         kInvalidUniqueId)
, x14c_bounds(-extent * 0.5f, extent * 0.5f)
, x164_origHInfo(hInfo)
, x16c_hInfo(hInfo)
, x174_dVuln(dVuln)
, x1dc_faceFlag(faceFlag)
, x254_fluidPlane(patternTex1, patternTex2, colorTex, 1.f, 2, EFluidType::NormalWater, 1.f, CFluidUVMotion(6.f, 0.f))
, x300_28_canOrbit(canOrbit == ECanOrbit::Orbit) {
  if (x1dc_faceFlag & 0x1) {
    x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.max.y(), 0.f);
    x1e4_faceDir = zeus::CTransform::RotateX(-M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x2) {
    x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.min.y(), 0.f);
    x1e4_faceDir = zeus::CTransform::RotateX(M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x4) {
    x244_faceTranslate = zeus::CVector3f(x14c_bounds.min.x(), 0.f, 0.f);
    x1e4_faceDir = zeus::CTransform::RotateY(-M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x8) {
    x244_faceTranslate = zeus::CVector3f(x14c_bounds.max.x(), 0.f, 0.f);
    x1e4_faceDir = zeus::CTransform::RotateY(M_PIF / 2.f);
  } else if (x1dc_faceFlag & 0x10) {
    x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.max.z());
    x1e4_faceDir = zeus::CTransform();
  } else if (x1dc_faceFlag & 0x20) {
    x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.min.z());
    x1e4_faceDir = zeus::CTransform::RotateY(M_PIF);
  }

  x214_faceDirInv = x1e4_faceDir.inverse();
}

void CScriptDamageableTrigger::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptDamageableTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
  switch (msg) {
  case EScriptObjectMessage::Deactivate:
    if (x30_24_active && x300_25_alphaOut) {
      return;
    }
    [[fallthrough]];
  case EScriptObjectMessage::Activate:
    if (!x30_24_active || x300_25_alphaOut) {
      x250_alphaTimer = 0.f;
      x16c_hInfo = x164_origHInfo;
      x300_25_alphaOut = false;
      if (x300_28_canOrbit) {
        AddMaterial(EMaterialTypes::Orbit, mgr);
      }
      SetLinkedObjectAlpha(0.f, mgr);
      x1e0_alpha = 0.f;
    }
    break;
  case EScriptObjectMessage::Damage:
    if (x300_27_invulnerable) {
      x16c_hInfo = x164_origHInfo;
    }
    break;
  case EScriptObjectMessage::Increment:
    x300_27_invulnerable = true;
    break;
  case EScriptObjectMessage::Decrement:
    x300_27_invulnerable = false;
    break;
  default:
    break;
  }

  CActor::AcceptScriptMsg(msg, sender, mgr);
}

EWeaponCollisionResponseTypes CScriptDamageableTrigger::GetCollisionResponseType(const zeus::CVector3f&,
                                                                                const zeus::CVector3f&,
                                                                                const CWeaponMode& weapMode,
                                                                                EProjectileAttrib) const {
  return x174_dVuln.WeaponHurts(weapMode, false) ? EWeaponCollisionResponseTypes::OtherProjectile
                                                 : EWeaponCollisionResponseTypes::Unknown15;
}

void CScriptDamageableTrigger::Render(CStateManager& mgr) {
  if (x30_24_active && x1dc_faceFlag != 0 && std::fabs(x1e0_alpha) >= 0.00001f) {
    const zeus::CAABox aabb = x14c_bounds.getTransformedAABox(x214_faceDirInv);
    const zeus::CTransform xf = x34_transform * zeus::CTransform::Translate(x244_faceTranslate) * x1e4_faceDir;
    x254_fluidPlane.Render(mgr, x1e0_alpha, aabb, xf, zeus::CTransform(), false, xe8_frustum, {},
                           kInvalidUniqueId, nullptr, 0, 0, zeus::skZero3f);
  }

  CActor::Render(mgr);
}

void CScriptDamageableTrigger::AddToRenderer(const zeus::CFrustum& /*frustum*/, CStateManager& mgr) {
  if (x300_26_outOfFrustum) {
    return;
  }

  EnsureRendered(mgr, GetTranslation() - x244_faceTranslate, GetSortingBounds(mgr));
}

void CScriptDamageableTrigger::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
  x300_26_outOfFrustum = !frustum.aabbFrustumTest(x14c_bounds.getTransformedAABox(x34_transform));

  if (x300_26_outOfFrustum) {
    return;
  }

  xe8_frustum = frustum;
  CActor::PreRender(mgr, frustum);
}

void CScriptDamageableTrigger::SetLinkedObjectAlpha(float a, CStateManager& mgr) {
  for (const SConnection& conn : x20_conns) {
    if (conn.x0_state != EScriptObjectState::MaxReached || conn.x4_msg != EScriptObjectMessage::Activate) {
      continue;
    }
    if (const TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) {
      if (!act->GetActive()) {
        act->SetActive(true);
      }
      act->SetDrawFlags(CModelFlags(5, 0, 3, zeus::CColor(1.f, a)));
    }
  }
}

float CScriptDamageableTrigger::GetPuddleAlphaScale() const {
  if (x250_alphaTimer <= 0.75f) {
    if (x300_25_alphaOut) {
      return 1.f - x250_alphaTimer / 0.75f;
    }
    return x250_alphaTimer / 0.75f;
  }

  if (x300_25_alphaOut) {
    return 0.f;
  }
  return 1.f;
}

void CScriptDamageableTrigger::Think(float dt, CStateManager& mgr) {
  if (!GetActive()) {
    return;
  }

  const CGameArea* area = mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways());
  const auto occState = area->IsPostConstructed() ? area->GetOcclusionState() : CGameArea::EOcclusionState::Occluded;
  x300_24_notOccluded = occState == CGameArea::EOcclusionState::Visible;

  if (x300_25_alphaOut) {
    if (x250_alphaTimer >= 0.75f) {
      SetActive(false);
      for (const SConnection& conn : x20_conns) {
        if (conn.x0_state != EScriptObjectState::MaxReached || conn.x4_msg != EScriptObjectMessage::Activate) {
          continue;
        }
        if (const TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) {
          act->SetActive(false);
        }
      }

      SetLinkedObjectAlpha(0.f, mgr);
      x300_25_alphaOut = false;
      return;
    }
  } else if (x16c_hInfo.GetHP() <= 0.f && x30_24_active) {
    SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None);
    RemoveMaterial(EMaterialTypes::Orbit, mgr);
    x300_25_alphaOut = true;
    x250_alphaTimer = 0.f;
  }

  if (x250_alphaTimer <= 0.75f) {
    x250_alphaTimer += dt;
  }

  const float objAlpha = GetPuddleAlphaScale();
  x1e0_alpha = 0.2f * objAlpha;
  SetLinkedObjectAlpha(objAlpha, mgr);
}

std::optional<zeus::CAABox> CScriptDamageableTrigger::GetTouchBounds() const {
  if (x30_24_active && x300_24_notOccluded) {
    return zeus::CAABox(x14c_bounds.min + GetTranslation(), x14c_bounds.max + GetTranslation());
  }
  return std::nullopt;
}

} // namespace urde
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "WebKitPrefix.h"
<commit_msg>Touch precompiled header wrapper to fix build.<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "WebKitPrefix.h"

<|endoftext|>


<commit_before>#include <ast/all.hh>
#include <ast/new-clone.hh>
#include <ast/parametric-ast.hh>
#include <object/symbols.hh>
#include <parser/ast-factory.hh>
#include <parser/parse.hh>
#include <parser/parse-result.hh>

namespace std
{
  ostream&
  operator<< (ostream& o, const parser::case_type& c)
  {
    return o << "/* " << (void*) &c << " */ "
             << "case "
             << libport::deref << c.first
             << " => "
             << libport::deref << c.second;
  }

  ostream&
  operator<< (ostream& o, const parser::cases_type& cs)
  {
    o << "/* " << (void*) &cs << " */ "
      << "{" << endl;
    foreach (const parser::case_type& c, cs)
      o << "  " << c << endl;
    return o << "}";
  }

}

namespace parser
{
  using ast::ParametricAst;

  ast::rExp
  ast_at(const yy::location& loc,
         ast::rExp cond,
         ast::rExp at, ast::rExp onleave,
         ast::rExp duration)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    if (duration)
    {
      static ast::ParametricAst desugar(
        "var '$at' = persist(%exp:1, %exp:2) |"
        "at ('$at') %exp:3 onleave %exp:4");

      return exp(desugar % cond % duration % at % onleave);
    }
    else
    {
      static ast::ParametricAst desugar(
        "Control.at_(%exp:1, detach(%exp:2), detach(%exp:3))");

      return exp(desugar % cond % at % onleave);
    }
  }

  ast::rExp
  ast_at_event(const ast::loc& loc,
               ast::rExp event, ast::rExp payload,
               ast::rExp at, ast::rExp onleave)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    static ast::ParametricAst desugar(
      "detach("
      "{"
      "  %exp:1.onEvent(closure ('$at')"
      "  {"
      "    if (Pattern.new(%exp:2).match('$at'.payload))"
      "    {"
      "      %exp:3 |"
      "      waituntil(!'$at'.active) |"
      "      %exp:4"
      "    }"
      "  })"
      "})");

    return exp(desugar % event % payload % at % onleave);
  }

  ast::rExp
  ast_whenever_event(const ast::loc& loc,
                     ast::rExp event, ast::rExp payload,
                     ast::rExp body, ast::rExp onleave)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    static ast::ParametricAst desugar(
      "detach("
      "{"
      "%exp:1.onEvent("
      "  closure ('$whenever')"
      "  {"
      "    if (Pattern.new(%exp:2).match('$whenever'.payload))"
      "      detach("
      "        {"
      "          while (true)"
      "          {"
      "            %exp:3 |"
      "            if(!'$whenever'.active)"
      "              break"
      "          } |"
      "          %exp:4"
      "        })"
      "  })"
      "})");

    return exp(desugar % event
               % payload
               % body % onleave);
  }

  /// Create a new Tree node composing \c Lhs and \c Rhs with \c Op.
  /// \param op must be & or |.
  ast::rExp
  ast_bin(const yy::location& l,
          ast::flavor_type op, ast::rExp lhs, ast::rExp rhs)
  {
    ast::rExp res = 0;
    assert (lhs);
    assert (rhs);
    switch (op)
    {
    case ast::flavor_pipe:
    {
      ast::rPipe pipe;
      if (pipe = lhs.unsafe_cast<ast::Pipe>())
        pipe->children_get().push_back(rhs);
      else
      {
        pipe = new ast::Pipe(l, ast::exps_type());
        pipe->children_get().push_back(lhs);
        pipe->children_get().push_back(rhs);
      }
      res = pipe;
      break;
    }
    case ast::flavor_and:
    {
      ast::rAnd rand;
      if (rand = lhs.unsafe_cast<ast::And>())
        rand->children_get().push_back(rhs);
      else
      {
        rand = new ast::And(l, ast::exps_type());
        rand->children_get().push_back(lhs);
        rand->children_get().push_back(rhs);
      }
      res = rand;
      break;
    }
    case ast::flavor_comma:
    case ast::flavor_semicolon:
    {
      ast::rNary nary = new ast::Nary(l);
      nary->push_back(lhs, op);
      nary->push_back(rhs);
      res = nary;
      break;
    }
    case ast::flavor_none:
      pabort(op);
    }
    return res;
  }

  /// "<method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            libport::Symbol method)
  {
    return ast_call(l, new ast::Implicit(l), method);
  }

  /// "<target> . <method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            ast::rExp target, libport::Symbol method, ast::exps_type* args)
  {
    return new ast::Call(l, args, target, method);
  }

  /// "<target> . <method> ()".
  ast::rCall
  ast_call(const yy::location& l, ast::rExp target, libport::Symbol method)
  {
    return ast_call(l, target, method, 0);
  }

  /// "<target> . <method> (<arg1>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::rExp arg1)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    return res;
  }

  /// "<target> . <method> (<arg1>, <arg2>)".
  /// "<target> . <method> (<arg1>, <arg2>, <arg3>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method,
           ast::rExp arg1, ast::rExp arg2, ast::rExp arg3)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    res->arguments_get()->push_back(arg2);
    if (arg3)
      res->arguments_get()->push_back(arg3);
    return res;
  }

  ast::rExp
  ast_closure(ast::rExp value)
  {
    static ast::ParametricAst a("closure () { %exp:1 }");
    return exp(a % value);
  }

  /// Build a for loop.
  // Since we don't have "continue", for is really a sugared
  // while:
  //
  // "for OP ( INIT; TEST; INC ) BODY"
  //
  // ->
  //
  // "{ INIT OP WHILE OP (TEST) { BODY | INC } }"
  //
  // OP is either ";" or "|".
  ast::rExp
  ast_for (const yy::location& l, ast::flavor_type op,
           ast::rExp init, ast::rExp test, ast::rExp inc,
           ast::rExp body)
  {
    passert(op, op == ast::flavor_pipe || op == ast::flavor_semicolon);
    assert(init);
    assert(test);
    assert(inc);
    assert(body);

    // BODY | INC.
    ast::rExp loop_body = ast_bin(l, ast::flavor_pipe, body, inc);

    // WHILE OP (TEST) { BODY | INC }.
    ast::While *while_loop =
      new ast::While(l, op, test, ast_scope(l, loop_body));

    // { INIT OP WHILE OP (TEST) { BODY | INC } }.
    return ast_scope(l, ast_bin(l, op, init, while_loop));
  }

  /// Return \a e in a ast::Scope unless it is already one.
  ast::rScope
  ast_scope(const yy::location& l, ast::rExp target, ast::rExp e)
  {
    if (ast::rScope res = e.unsafe_cast<ast::Scope>())
      return res;
    else if (target)
      return new ast::Do(l, e, target);
    else
      return new ast::Scope(l, e);
  }

  ast::rScope
  ast_scope(const yy::location& l, ast::rExp e)
  {
    return ast_scope(l, 0, e);
  }

  ast::rExp
  ast_string(const yy::location& l, libport::Symbol s)
  {
    return new ast::String(l, s);
  }

  ast::rExp
  ast_switch(const yy::location& l, ast::rExp cond, const cases_type& cases)
  {
    (void) l;

    static ast::ParametricAst nil("nil");
    ast::rExp inner = exp(nil);
    rforeach (const case_type& c, cases)
    {
      static ast::ParametricAst a(
        "if (Pattern.new(%exp:1).match('$switch')) %exp:2 else %exp:3");
      a % c.first
        % c.second
        % inner;
      inner = ast::exp(a);
    }

    static ParametricAst sw("{ var '$switch' = %exp:1 | %exp:2 }");
    return exp(sw % cond % inner);
  }

  ast::rLValue ast_lvalue_once(const ast::rLValue& lvalue)
  {
    ast::rCall tmp = ast_call(lvalue->location_get(), SYMBOL($tmp));

    if (lvalue->call()->target_implicit())
      return lvalue.get();
    else
      return ast_call(lvalue->location_get(), tmp, lvalue->call()->name_get());
  }

  ast::rExp ast_lvalue_wrap(const ast::rLValue& lvalue, const ast::rExp& e)
  {
    static ParametricAst wrap(
      "{"
      "var '$tmp' = %exp:1;"
      "%exp:2;"
      "}"
      );

    if (lvalue->call()->target_implicit())
      return e;
    else
    {
      wrap % lvalue->call()->target_get() % e;
      return exp(wrap);
    }
  }

}
<commit_msg>Fix for loop desugaring: execute the increment on `continue'.<commit_after>#include <ast/all.hh>
#include <ast/new-clone.hh>
#include <ast/parametric-ast.hh>
#include <object/symbols.hh>
#include <parser/ast-factory.hh>
#include <parser/parse.hh>
#include <parser/parse-result.hh>

namespace std
{
  ostream&
  operator<< (ostream& o, const parser::case_type& c)
  {
    return o << "/* " << (void*) &c << " */ "
             << "case "
             << libport::deref << c.first
             << " => "
             << libport::deref << c.second;
  }

  ostream&
  operator<< (ostream& o, const parser::cases_type& cs)
  {
    o << "/* " << (void*) &cs << " */ "
      << "{" << endl;
    foreach (const parser::case_type& c, cs)
      o << "  " << c << endl;
    return o << "}";
  }

}

namespace parser
{
  using ast::ParametricAst;

  ast::rExp
  ast_at(const yy::location& loc,
         ast::rExp cond,
         ast::rExp at, ast::rExp onleave,
         ast::rExp duration)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    if (duration)
    {
      static ast::ParametricAst desugar(
        "var '$at' = persist(%exp:1, %exp:2) |"
        "at ('$at') %exp:3 onleave %exp:4");

      return exp(desugar % cond % duration % at % onleave);
    }
    else
    {
      static ast::ParametricAst desugar(
        "Control.at_(%exp:1, detach(%exp:2), detach(%exp:3))");

      return exp(desugar % cond % at % onleave);
    }
  }

  ast::rExp
  ast_at_event(const ast::loc& loc,
               ast::rExp event, ast::rExp payload,
               ast::rExp at, ast::rExp onleave)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    static ast::ParametricAst desugar(
      "detach("
      "{"
      "  %exp:1.onEvent(closure ('$at')"
      "  {"
      "    if (Pattern.new(%exp:2).match('$at'.payload))"
      "    {"
      "      %exp:3 |"
      "      waituntil(!'$at'.active) |"
      "      %exp:4"
      "    }"
      "  })"
      "})");

    return exp(desugar % event % payload % at % onleave);
  }

  ast::rExp
  ast_whenever_event(const ast::loc& loc,
                     ast::rExp event, ast::rExp payload,
                     ast::rExp body, ast::rExp onleave)
  {
    if (!onleave)
      onleave = new ast::Noop(loc, 0);

    static ast::ParametricAst desugar(
      "detach("
      "{"
      "%exp:1.onEvent("
      "  closure ('$whenever')"
      "  {"
      "    if (Pattern.new(%exp:2).match('$whenever'.payload))"
      "      detach("
      "        {"
      "          while (true)"
      "          {"
      "            %exp:3 |"
      "            if(!'$whenever'.active)"
      "              break"
      "          } |"
      "          %exp:4"
      "        })"
      "  })"
      "})");

    return exp(desugar % event
               % payload
               % body % onleave);
  }

  /// Create a new Tree node composing \c Lhs and \c Rhs with \c Op.
  /// \param op must be & or |.
  ast::rExp
  ast_bin(const yy::location& l,
          ast::flavor_type op, ast::rExp lhs, ast::rExp rhs)
  {
    ast::rExp res = 0;
    assert (lhs);
    assert (rhs);
    switch (op)
    {
    case ast::flavor_pipe:
    {
      ast::rPipe pipe;
      if (pipe = lhs.unsafe_cast<ast::Pipe>())
        pipe->children_get().push_back(rhs);
      else
      {
        pipe = new ast::Pipe(l, ast::exps_type());
        pipe->children_get().push_back(lhs);
        pipe->children_get().push_back(rhs);
      }
      res = pipe;
      break;
    }
    case ast::flavor_and:
    {
      ast::rAnd rand;
      if (rand = lhs.unsafe_cast<ast::And>())
        rand->children_get().push_back(rhs);
      else
      {
        rand = new ast::And(l, ast::exps_type());
        rand->children_get().push_back(lhs);
        rand->children_get().push_back(rhs);
      }
      res = rand;
      break;
    }
    case ast::flavor_comma:
    case ast::flavor_semicolon:
    {
      ast::rNary nary = new ast::Nary(l);
      nary->push_back(lhs, op);
      nary->push_back(rhs);
      res = nary;
      break;
    }
    case ast::flavor_none:
      pabort(op);
    }
    return res;
  }

  /// "<method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            libport::Symbol method)
  {
    return ast_call(l, new ast::Implicit(l), method);
  }

  /// "<target> . <method> (args)".
  ast::rCall
  ast_call (const yy::location& l,
            ast::rExp target, libport::Symbol method, ast::exps_type* args)
  {
    return new ast::Call(l, args, target, method);
  }

  /// "<target> . <method> ()".
  ast::rCall
  ast_call(const yy::location& l, ast::rExp target, libport::Symbol method)
  {
    return ast_call(l, target, method, 0);
  }

  /// "<target> . <method> (<arg1>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method, ast::rExp arg1)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    return res;
  }

  /// "<target> . <method> (<arg1>, <arg2>)".
  /// "<target> . <method> (<arg1>, <arg2>, <arg3>)".
  ast::rCall
  ast_call(const yy::location& l,
           ast::rExp target, libport::Symbol method,
           ast::rExp arg1, ast::rExp arg2, ast::rExp arg3)
  {
    ast::rCall res = ast_call(l, target, method, new ast::exps_type);
    res->arguments_get()->push_back(arg1);
    res->arguments_get()->push_back(arg2);
    if (arg3)
      res->arguments_get()->push_back(arg3);
    return res;
  }

  ast::rExp
  ast_closure(ast::rExp value)
  {
    static ast::ParametricAst a("closure () { %exp:1 }");
    return exp(a % value);
  }

  /// Build a for loop.
  // The increment is included directly in the condition to make sure
  // it is executed on `continue'.
  ast::rExp
  ast_for (const yy::location&, ast::flavor_type,
           ast::rExp init, ast::rExp test, ast::rExp inc,
           ast::rExp body)
  {
    // FIXME: for| is handled as a simple for
    static ParametricAst desugar(

      "{"
      "  %exp:1 |"
      "  var '$tmp-for-first' = true |"
      "  while ({ if ('$tmp-for-first') '$tmp-for-first' = false else %exp:2 | %exp:3})"
      "    %exp:4 |"
      "}"
      );

    desugar
      % init
      % inc
      % test
      % body;

    return exp(desugar);
  }

  /// Return \a e in a ast::Scope unless it is already one.
  ast::rScope
  ast_scope(const yy::location& l, ast::rExp target, ast::rExp e)
  {
    if (ast::rScope res = e.unsafe_cast<ast::Scope>())
      return res;
    else if (target)
      return new ast::Do(l, e, target);
    else
      return new ast::Scope(l, e);
  }

  ast::rScope
  ast_scope(const yy::location& l, ast::rExp e)
  {
    return ast_scope(l, 0, e);
  }

  ast::rExp
  ast_string(const yy::location& l, libport::Symbol s)
  {
    return new ast::String(l, s);
  }

  ast::rExp
  ast_switch(const yy::location& l, ast::rExp cond, const cases_type& cases)
  {
    (void) l;

    static ast::ParametricAst nil("nil");
    ast::rExp inner = exp(nil);
    rforeach (const case_type& c, cases)
    {
      static ast::ParametricAst a(
        "if (Pattern.new(%exp:1).match('$switch')) %exp:2 else %exp:3");
      a % c.first
        % c.second
        % inner;
      inner = ast::exp(a);
    }

    static ParametricAst sw("{ var '$switch' = %exp:1 | %exp:2 }");
    return exp(sw % cond % inner);
  }

  ast::rLValue ast_lvalue_once(const ast::rLValue& lvalue)
  {
    ast::rCall tmp = ast_call(lvalue->location_get(), SYMBOL($tmp));

    if (lvalue->call()->target_implicit())
      return lvalue.get();
    else
      return ast_call(lvalue->location_get(), tmp, lvalue->call()->name_get());
  }

  ast::rExp ast_lvalue_wrap(const ast::rLValue& lvalue, const ast::rExp& e)
  {
    static ParametricAst wrap(
      "{"
      "var '$tmp' = %exp:1;"
      "%exp:2;"
      "}"
      );

    if (lvalue->call()->target_implicit())
      return e;
    else
    {
      wrap % lvalue->call()->target_get() % e;
      return exp(wrap);
    }
  }

}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/info_bubble.h"

#include "app/gfx/canvas.h"
#include "app/gfx/color_utils.h"
#include "app/gfx/path.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/notification_service.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"

namespace {

// Background color of the bubble.
#if defined(OS_WIN)
const SkColor kBackgroundColor = color_utils::GetSysSkColor(COLOR_WINDOW);
#else
// TODO(beng): source from theme provider.
const SkColor kBackgroundColor = SK_ColorWHITE;
#endif

}

// BorderContents -------------------------------------------------------------

// This is used to paint the border of the InfoBubble.  Windows uses this via
// BorderWidget (see below), while others can use it directly in the bubble.
class BorderContents : public views::View {
 public:
  BorderContents() { }

  // Given the size of the contents and the rect to point at, initializes the
  // bubble and returns the bounds of both the border
  // and the contents inside the bubble.
  // |is_rtl| is true if the UI is RTL and thus the arrow should default to the
  // right side of the bubble; otherwise it defaults to the left top corner, and
  // then is moved as necessary to try and fit the whole bubble on the same
  // monitor as the rect being pointed to.
  //
  // TODO(pkasting): Maybe this should use mirroring transformations instead,
  // which would hopefully simplify this code.
  void InitAndGetBounds(
      const gfx::Rect& position_relative_to,  // In screen coordinates
      const gfx::Size& contents_size,
      bool is_rtl,
      gfx::Rect* contents_bounds,             // Returned in window coordinates
      gfx::Rect* window_bounds);              // Returned in screen coordinates

 private:
  virtual ~BorderContents() { }

  // Overridden from View:
  virtual void Paint(gfx::Canvas* canvas);

  DISALLOW_COPY_AND_ASSIGN(BorderContents);
};

void BorderContents::InitAndGetBounds(
    const gfx::Rect& position_relative_to,
    const gfx::Size& contents_size,
    bool is_rtl,
    gfx::Rect* contents_bounds,
    gfx::Rect* window_bounds) {
  // Margins between the contents and the inside of the border, in pixels.
  const int kLeftMargin = 6;
  const int kTopMargin = 6;
  const int kRightMargin = 6;
  const int kBottomMargin = 9;

  // Set the border.
  BubbleBorder* bubble_border = new BubbleBorder;
  set_border(bubble_border);
  bubble_border->set_background_color(kBackgroundColor);

  // Give the contents a margin.
  gfx::Size local_contents_size(contents_size);
  local_contents_size.Enlarge(kLeftMargin + kRightMargin,
                              kTopMargin + kBottomMargin);

  // Try putting the arrow in its default location, and calculating the bounds.
  BubbleBorder::ArrowLocation arrow_location(is_rtl ?
      BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT);
  bubble_border->set_arrow_location(arrow_location);
  *window_bounds =
      bubble_border->GetBounds(position_relative_to, local_contents_size);

  // See if those bounds will fit on the monitor.
  scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
      WindowSizer::CreateDefaultMonitorInfoProvider());
  gfx::Rect monitor_bounds(
      monitor_provider->GetMonitorWorkAreaMatching(position_relative_to));
  if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*window_bounds)) {
    // The bounds don't fit.  Move the arrow to try and improve things.
    bool arrow_on_left =
        (is_rtl ? (window_bounds->x() < monitor_bounds.x()) :
                  (window_bounds->right() <= monitor_bounds.right()));
    if (window_bounds->bottom() > monitor_bounds.bottom()) {
      arrow_location = arrow_on_left ?
          BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT;
    } else {
      arrow_location = arrow_on_left ?
          BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
    }
    bubble_border->set_arrow_location(arrow_location);

    // Now get the recalculated bounds.
    *window_bounds = bubble_border->GetBounds(position_relative_to,
                                              local_contents_size);
  }

  // Calculate the bounds of the contained contents (in window coordinates) by
  // subtracting the border dimensions and margin amounts.
  *contents_bounds = gfx::Rect(gfx::Point(), window_bounds->size());
  gfx::Insets insets;
  bubble_border->GetInsets(&insets);
  contents_bounds->Inset(insets.left() + kLeftMargin, insets.top() + kTopMargin,
      insets.right() + kRightMargin, insets.bottom() + kBottomMargin);
}

void BorderContents::Paint(gfx::Canvas* canvas) {
  // The border of this view creates an anti-aliased round-rect region for the
  // contents, which we need to fill with the background color.
  SkPaint paint;
  paint.setAntiAlias(true);
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(kBackgroundColor);
  gfx::Path path;
  gfx::Rect bounds(GetLocalBounds(false));
  SkRect rect;
  rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
           SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
  SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
  path.addRoundRect(rect, radius, radius);
  canvas->drawPath(path, paint);

  // Now we paint the border, so it will be alpha-blended atop the contents.
  // This looks slightly better in the corners than drawing the contents atop
  // the border.
  PaintBorder(canvas);
}

#if defined(OS_WIN)
// BorderWidget ---------------------------------------------------------------

BorderWidget::BorderWidget() {
  set_delete_on_destroy(false);  // Our owner will free us manually.
  set_window_style(WS_POPUP);
  set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
}

gfx::Rect BorderWidget::InitAndGetBounds(
    HWND owner,
    const gfx::Rect& position_relative_to,
    const gfx::Size& contents_size,
    bool is_rtl) {
  // Set up the border view and ask it to calculate our bounds (and our
  // contents').
  BorderContents* border_contents = new BorderContents;
  gfx::Rect contents_bounds, window_bounds;
  border_contents->InitAndGetBounds(position_relative_to, contents_size, is_rtl,
                                    &contents_bounds, &window_bounds);

  // Initialize ourselves.
  WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds);
  SetContentsView(border_contents);
  SetWindowPos(owner, 0, 0, 0, 0,
               SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW);

  // Chop a hole out of our region to show the contents through.
  // CreateRectRgn() expects (left, top, right, bottom) in window coordinates.
  HRGN contents_region = CreateRectRgn(contents_bounds.x(), contents_bounds.y(),
      contents_bounds.right(), contents_bounds.bottom());
  HRGN window_region = CreateRectRgn(0, 0, window_bounds.width(),
                                     window_bounds.height());
  CombineRgn(window_region, window_region, contents_region, RGN_XOR);
  DeleteObject(contents_region);
  SetWindowRgn(window_region, true);

  // Return |contents_bounds| in screen coordinates.
  contents_bounds.Offset(window_bounds.origin());
  return contents_bounds;
}

LRESULT BorderWidget::OnMouseActivate(HWND window,
                                      UINT hit_test,
                                      UINT mouse_message) {
  // Never activate.
  return MA_NOACTIVATE;
}
#endif

// InfoBubble -----------------------------------------------------------------

// static
InfoBubble* InfoBubble::Show(views::Window* parent,
                             const gfx::Rect& position_relative_to,
                             views::View* contents,
                             InfoBubbleDelegate* delegate) {
  InfoBubble* window = new InfoBubble;
  window->Init(parent, position_relative_to, contents, delegate);
  return window;
}

void InfoBubble::Close() {
  Close(false);
}

InfoBubble::InfoBubble()
    :
#if defined(OS_LINUX)
      WidgetGtk(TYPE_POPUP),
#endif
      delegate_(NULL),
      parent_(NULL),
      closed_(false) {
}

void InfoBubble::Init(views::Window* parent,
                      const gfx::Rect& position_relative_to,
                      views::View* contents,
                      InfoBubbleDelegate* delegate) {
  parent_ = parent;
  parent_->DisableInactiveRendering();
  delegate_ = delegate;

  // Create the main window.
#if defined(OS_WIN)
  set_window_style(WS_POPUP | WS_CLIPCHILDREN);
  set_window_ex_style(WS_EX_TOOLWINDOW);
  WidgetWin::Init(parent->GetNativeWindow(), gfx::Rect());
#elif defined(OS_LINUX)
  MakeTransparent();
  WidgetGtk::Init(GTK_WIDGET(parent->GetNativeWindow()), gfx::Rect());
#endif

  // Create a View to hold the contents of the main window.
  views::View* contents_view = new views::View;
  // Adding |contents| as a child has to be done before we call
  // contents->GetPreferredSize() below, since some supplied views don't
  // actually initialize themselves until they're added to a hierarchy.
  contents_view->AddChildView(contents);
  SetContentsView(contents_view);

  // Calculate and set the bounds for all windows and views.
  gfx::Rect window_bounds;
#if defined(OS_WIN)
  border_.reset(new BorderWidget);
  // Initialize and position the border window.
  window_bounds = border_->InitAndGetBounds(GetNativeView(),
      position_relative_to, contents->GetPreferredSize(),
      contents->UILayoutIsRightToLeft());

  // Make |contents| take up the entire contents view.
  contents_view->SetLayoutManager(new views::FillLayout);

  // Paint the background color behind the contents.
  contents_view->set_background(
      views::Background::CreateSolidBackground(kBackgroundColor));
#else
  // Create a view to paint the border and background.
  BorderContents* border_contents = new BorderContents;
  gfx::Rect contents_bounds;
  border_contents->InitAndGetBounds(position_relative_to,
      contents->GetPreferredSize(), is_rtl, &contents_bounds, &window_bounds);
  // This new view must be added before |contents| so it will paint under it.
  contents_view->AddChildView(border_contents, 0);

  // |contents_view| has no layout manager, so we have to explicitly position
  // its children.
  border_contents->SetBounds(gfx::Rect(gfx::Point(), window_bounds.size()));
  contents->SetBounds(contents_bounds);
#endif
  SetBounds(window_bounds);

#if defined(OS_WIN)
  // Register the Escape accelerator for closing.
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(VK_ESCAPE, false, false, false), this);
#endif

  // Done creating the bubble.
  NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED,
                                         Source<InfoBubble>(this),
                                         NotificationService::NoDetails());

  // Show the window.
#if defined(OS_WIN)
  border_->ShowWindow(SW_SHOW);
  ShowWindow(SW_SHOW);
#elif defined(OS_LINUX)
  views::WidgetGtk::Show();
#endif
}

#if defined(OS_WIN)
void InfoBubble::OnActivate(UINT action, BOOL minimized, HWND window) {
  // The popup should close when it is deactivated.
  if (action == WA_INACTIVE && !closed_) {
    Close();
  } else if (action == WA_ACTIVE) {
    DCHECK(GetRootView()->GetChildViewCount() > 0);
    GetRootView()->GetChildViewAt(0)->RequestFocus();
  }
}
#endif

void InfoBubble::Close(bool closed_by_escape) {
  if (closed_)
    return;

  if (delegate_)
    delegate_->InfoBubbleClosing(this, closed_by_escape);
  closed_ = true;
#if defined(OS_WIN)
  border_->Close();
  WidgetWin::Close();
#elif defined(OS_LINUX)
  WidgetGtk::Close();
#endif
}

bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) {
  if (!delegate_ || delegate_->CloseOnEscape()) {
    Close(true);
    return true;
  }
  return false;
}
<commit_msg>Fix the Linux Views build, sigh.  We need a trybot.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/info_bubble.h"

#include "app/gfx/canvas.h"
#include "app/gfx/color_utils.h"
#include "app/gfx/path.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/notification_service.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"

namespace {

// Background color of the bubble.
#if defined(OS_WIN)
const SkColor kBackgroundColor = color_utils::GetSysSkColor(COLOR_WINDOW);
#else
// TODO(beng): source from theme provider.
const SkColor kBackgroundColor = SK_ColorWHITE;
#endif

}

// BorderContents -------------------------------------------------------------

// This is used to paint the border of the InfoBubble.  Windows uses this via
// BorderWidget (see below), while others can use it directly in the bubble.
class BorderContents : public views::View {
 public:
  BorderContents() { }

  // Given the size of the contents and the rect to point at, initializes the
  // bubble and returns the bounds of both the border
  // and the contents inside the bubble.
  // |is_rtl| is true if the UI is RTL and thus the arrow should default to the
  // right side of the bubble; otherwise it defaults to the left top corner, and
  // then is moved as necessary to try and fit the whole bubble on the same
  // monitor as the rect being pointed to.
  //
  // TODO(pkasting): Maybe this should use mirroring transformations instead,
  // which would hopefully simplify this code.
  void InitAndGetBounds(
      const gfx::Rect& position_relative_to,  // In screen coordinates
      const gfx::Size& contents_size,
      bool is_rtl,
      gfx::Rect* contents_bounds,             // Returned in window coordinates
      gfx::Rect* window_bounds);              // Returned in screen coordinates

 private:
  virtual ~BorderContents() { }

  // Overridden from View:
  virtual void Paint(gfx::Canvas* canvas);

  DISALLOW_COPY_AND_ASSIGN(BorderContents);
};

void BorderContents::InitAndGetBounds(
    const gfx::Rect& position_relative_to,
    const gfx::Size& contents_size,
    bool is_rtl,
    gfx::Rect* contents_bounds,
    gfx::Rect* window_bounds) {
  // Margins between the contents and the inside of the border, in pixels.
  const int kLeftMargin = 6;
  const int kTopMargin = 6;
  const int kRightMargin = 6;
  const int kBottomMargin = 9;

  // Set the border.
  BubbleBorder* bubble_border = new BubbleBorder;
  set_border(bubble_border);
  bubble_border->set_background_color(kBackgroundColor);

  // Give the contents a margin.
  gfx::Size local_contents_size(contents_size);
  local_contents_size.Enlarge(kLeftMargin + kRightMargin,
                              kTopMargin + kBottomMargin);

  // Try putting the arrow in its default location, and calculating the bounds.
  BubbleBorder::ArrowLocation arrow_location(is_rtl ?
      BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT);
  bubble_border->set_arrow_location(arrow_location);
  *window_bounds =
      bubble_border->GetBounds(position_relative_to, local_contents_size);

  // See if those bounds will fit on the monitor.
  scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
      WindowSizer::CreateDefaultMonitorInfoProvider());
  gfx::Rect monitor_bounds(
      monitor_provider->GetMonitorWorkAreaMatching(position_relative_to));
  if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*window_bounds)) {
    // The bounds don't fit.  Move the arrow to try and improve things.
    bool arrow_on_left =
        (is_rtl ? (window_bounds->x() < monitor_bounds.x()) :
                  (window_bounds->right() <= monitor_bounds.right()));
    if (window_bounds->bottom() > monitor_bounds.bottom()) {
      arrow_location = arrow_on_left ?
          BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT;
    } else {
      arrow_location = arrow_on_left ?
          BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
    }
    bubble_border->set_arrow_location(arrow_location);

    // Now get the recalculated bounds.
    *window_bounds = bubble_border->GetBounds(position_relative_to,
                                              local_contents_size);
  }

  // Calculate the bounds of the contained contents (in window coordinates) by
  // subtracting the border dimensions and margin amounts.
  *contents_bounds = gfx::Rect(gfx::Point(), window_bounds->size());
  gfx::Insets insets;
  bubble_border->GetInsets(&insets);
  contents_bounds->Inset(insets.left() + kLeftMargin, insets.top() + kTopMargin,
      insets.right() + kRightMargin, insets.bottom() + kBottomMargin);
}

void BorderContents::Paint(gfx::Canvas* canvas) {
  // The border of this view creates an anti-aliased round-rect region for the
  // contents, which we need to fill with the background color.
  SkPaint paint;
  paint.setAntiAlias(true);
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(kBackgroundColor);
  gfx::Path path;
  gfx::Rect bounds(GetLocalBounds(false));
  SkRect rect;
  rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
           SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
  SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
  path.addRoundRect(rect, radius, radius);
  canvas->drawPath(path, paint);

  // Now we paint the border, so it will be alpha-blended atop the contents.
  // This looks slightly better in the corners than drawing the contents atop
  // the border.
  PaintBorder(canvas);
}

#if defined(OS_WIN)
// BorderWidget ---------------------------------------------------------------

BorderWidget::BorderWidget() {
  set_delete_on_destroy(false);  // Our owner will free us manually.
  set_window_style(WS_POPUP);
  set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
}

gfx::Rect BorderWidget::InitAndGetBounds(
    HWND owner,
    const gfx::Rect& position_relative_to,
    const gfx::Size& contents_size,
    bool is_rtl) {
  // Set up the border view and ask it to calculate our bounds (and our
  // contents').
  BorderContents* border_contents = new BorderContents;
  gfx::Rect contents_bounds, window_bounds;
  border_contents->InitAndGetBounds(position_relative_to, contents_size, is_rtl,
                                    &contents_bounds, &window_bounds);

  // Initialize ourselves.
  WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds);
  SetContentsView(border_contents);
  SetWindowPos(owner, 0, 0, 0, 0,
               SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW);

  // Chop a hole out of our region to show the contents through.
  // CreateRectRgn() expects (left, top, right, bottom) in window coordinates.
  HRGN contents_region = CreateRectRgn(contents_bounds.x(), contents_bounds.y(),
      contents_bounds.right(), contents_bounds.bottom());
  HRGN window_region = CreateRectRgn(0, 0, window_bounds.width(),
                                     window_bounds.height());
  CombineRgn(window_region, window_region, contents_region, RGN_XOR);
  DeleteObject(contents_region);
  SetWindowRgn(window_region, true);

  // Return |contents_bounds| in screen coordinates.
  contents_bounds.Offset(window_bounds.origin());
  return contents_bounds;
}

LRESULT BorderWidget::OnMouseActivate(HWND window,
                                      UINT hit_test,
                                      UINT mouse_message) {
  // Never activate.
  return MA_NOACTIVATE;
}
#endif

// InfoBubble -----------------------------------------------------------------

// static
InfoBubble* InfoBubble::Show(views::Window* parent,
                             const gfx::Rect& position_relative_to,
                             views::View* contents,
                             InfoBubbleDelegate* delegate) {
  InfoBubble* window = new InfoBubble;
  window->Init(parent, position_relative_to, contents, delegate);
  return window;
}

void InfoBubble::Close() {
  Close(false);
}

InfoBubble::InfoBubble()
    :
#if defined(OS_LINUX)
      WidgetGtk(TYPE_POPUP),
#endif
      delegate_(NULL),
      parent_(NULL),
      closed_(false) {
}

void InfoBubble::Init(views::Window* parent,
                      const gfx::Rect& position_relative_to,
                      views::View* contents,
                      InfoBubbleDelegate* delegate) {
  parent_ = parent;
  parent_->DisableInactiveRendering();
  delegate_ = delegate;

  // Create the main window.
#if defined(OS_WIN)
  set_window_style(WS_POPUP | WS_CLIPCHILDREN);
  set_window_ex_style(WS_EX_TOOLWINDOW);
  WidgetWin::Init(parent->GetNativeWindow(), gfx::Rect());
#elif defined(OS_LINUX)
  MakeTransparent();
  WidgetGtk::Init(GTK_WIDGET(parent->GetNativeWindow()), gfx::Rect());
#endif

  // Create a View to hold the contents of the main window.
  views::View* contents_view = new views::View;
  // Adding |contents| as a child has to be done before we call
  // contents->GetPreferredSize() below, since some supplied views don't
  // actually initialize themselves until they're added to a hierarchy.
  contents_view->AddChildView(contents);
  SetContentsView(contents_view);

  // Calculate and set the bounds for all windows and views.
  gfx::Rect window_bounds;
#if defined(OS_WIN)
  border_.reset(new BorderWidget);
  // Initialize and position the border window.
  window_bounds = border_->InitAndGetBounds(GetNativeView(),
      position_relative_to, contents->GetPreferredSize(),
      contents->UILayoutIsRightToLeft());

  // Make |contents| take up the entire contents view.
  contents_view->SetLayoutManager(new views::FillLayout);

  // Paint the background color behind the contents.
  contents_view->set_background(
      views::Background::CreateSolidBackground(kBackgroundColor));
#else
  // Create a view to paint the border and background.
  BorderContents* border_contents = new BorderContents;
  gfx::Rect contents_bounds;
  border_contents->InitAndGetBounds(position_relative_to,
      contents->GetPreferredSize(), contents->UILayoutIsRightToLeft(),
      &contents_bounds, &window_bounds);
  // This new view must be added before |contents| so it will paint under it.
  contents_view->AddChildView(0, border_contents);

  // |contents_view| has no layout manager, so we have to explicitly position
  // its children.
  border_contents->SetBounds(gfx::Rect(gfx::Point(), window_bounds.size()));
  contents->SetBounds(contents_bounds);
#endif
  SetBounds(window_bounds);

#if defined(OS_WIN)
  // Register the Escape accelerator for closing.
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(VK_ESCAPE, false, false, false), this);
#endif

  // Done creating the bubble.
  NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED,
                                         Source<InfoBubble>(this),
                                         NotificationService::NoDetails());

  // Show the window.
#if defined(OS_WIN)
  border_->ShowWindow(SW_SHOW);
  ShowWindow(SW_SHOW);
#elif defined(OS_LINUX)
  views::WidgetGtk::Show();
#endif
}

#if defined(OS_WIN)
void InfoBubble::OnActivate(UINT action, BOOL minimized, HWND window) {
  // The popup should close when it is deactivated.
  if (action == WA_INACTIVE && !closed_) {
    Close();
  } else if (action == WA_ACTIVE) {
    DCHECK(GetRootView()->GetChildViewCount() > 0);
    GetRootView()->GetChildViewAt(0)->RequestFocus();
  }
}
#endif

void InfoBubble::Close(bool closed_by_escape) {
  if (closed_)
    return;

  if (delegate_)
    delegate_->InfoBubbleClosing(this, closed_by_escape);
  closed_ = true;
#if defined(OS_WIN)
  border_->Close();
  WidgetWin::Close();
#elif defined(OS_LINUX)
  WidgetGtk::Close();
#endif
}

bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) {
  if (!delegate_ || delegate_->CloseOnEscape()) {
    Close(true);
    return true;
  }
  return false;
}
<|endoftext|>


<commit_before>#include "filepickerwidget.h"

#include "debug.h"

#include <QKeyEvent>
#include <QPersistentModelIndex>
#include <QSettings>

FilePickerWidget::FilePickerWidget(QWidget *parent)
    : QWidget(parent)
{
    _ui.setupUi(this);
    _ui.optionsContainer->hide();

    _model.setRootPath(QDir::rootPath());
    //    _model.setNameFilterDisables(false);
    _ui.treeView->setModel(&_model);
    _ui.treeView->installEventFilter(this);
    QSettings settings;
    setCurrentPath(
        settings.value("app/file_browse_last", QDir::homePath()).toString());
    _completer.setModel(&_model);
    _completer.setCompletionMode(QCompleter::InlineCompletion);
    _completer.setCaseSensitivity(Qt::CaseSensitive);
    _ui.filterLineEdit->setCompleter(&_completer);
    _ui.treeView->setColumnWidth(0, 250);
    _ui.filterLineEdit->setFocus();

    connect(&_model, &CustomFileSystemModel::dataChanged,
            [&](const QModelIndex &topLeft, const QModelIndex &bottomRight,
                const QVector<int> &roles) {
                Q_UNUSED(topLeft);
                Q_UNUSED(bottomRight);
                if(!roles.isEmpty() && (roles.first() == SELECTION_CHANGED_ROLE))
                    emit selectionChanged();
            });
    connect(_ui.filterLineEdit, &QLineEdit::textEdited, this,
            &FilePickerWidget::updateFilter);
    connect(_ui.showHiddenCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::Hidden);
        else
            _model.setFilter(_model.filter() & ~QDir::Hidden);
        emit settingChanged();
    });
    connect(_ui.showSystemCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::System);
        else
            _model.setFilter(_model.filter() & ~QDir::System);
        emit settingChanged();
    });
    connect(_ui.hideLinksCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::NoSymLinks);
        else
            _model.setFilter(_model.filter() & ~QDir::NoSymLinks);
        emit settingChanged();
    });
    connect(_ui.showOptionsButton, &QPushButton::clicked, [&]() {
        _ui.optionsContainer->setVisible(!_ui.optionsContainer->isVisible());
    });
    connect(_ui.filterLineEdit, &QLineEdit::returnPressed, [&]() {
        if(_completer.currentCompletion().isEmpty())
            _ui.treeView->setFocus();
    });
    connect(_ui.homeButton, &QPushButton::clicked,
            [&]() { setCurrentPath(QDir::homePath()); });
}

FilePickerWidget::~FilePickerWidget()
{
}

void FilePickerWidget::reset()
{
    _model.reset();
    _ui.treeView->reset();
    QSettings settings;
    setCurrentPath(
        settings.value("app/file_browse_last", QDir::homePath()).toString());
}

QList<QUrl> FilePickerWidget::getSelectedUrls()
{
    QList<QUrl> urls;
    QList<QPersistentModelIndex> indexList = _model.checkedIndexes();
    foreach(QPersistentModelIndex index, indexList)
        urls << QUrl::fromUserInput(_model.filePath(index));
    return urls;
}

void FilePickerWidget::setSelectedUrls(const QList<QUrl> &urls)
{
    _model.reset();
    foreach(const QUrl url, urls)
    {
        _model.setData(_model.index(url.toLocalFile()), Qt::Checked,
                       Qt::CheckStateRole);
    }
}

void FilePickerWidget::selectUrl(QUrl url)
{
    _model.setData(_model.index(url.toLocalFile()), Qt::Checked,
                   Qt::CheckStateRole);
}

bool FilePickerWidget::settingShowHidden()
{
    return _ui.showHiddenCheckBox->isChecked();
}

void FilePickerWidget::setSettingShowHidden(bool showHidden)
{
    _ui.showHiddenCheckBox->setChecked(showHidden);
}

bool FilePickerWidget::settingShowSystem()
{
    return _ui.showSystemCheckBox->isChecked();
}

void FilePickerWidget::setSettingShowSystem(bool showSystem)
{
    _ui.showSystemCheckBox->setChecked(showSystem);
}

bool FilePickerWidget::settingHideSymlinks()
{
    return _ui.hideLinksCheckBox->isChecked();
}

void FilePickerWidget::setSettingHideSymlinks(bool hideSymlinks)
{
    _ui.hideLinksCheckBox->setChecked(hideSymlinks);
}

void FilePickerWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Escape:
        if(_ui.optionsContainer->isVisible())
        {
            _ui.optionsContainer->hide();
        }
        else if(!_ui.filterLineEdit->hasFocus())
        {
            _ui.filterLineEdit->setFocus();
        }
        else
        {
            QWidget::keyPressEvent(event);
        }
        break;
    default:
        QWidget::keyPressEvent(event);
    }
}

bool FilePickerWidget::eventFilter(QObject *obj, QEvent *event)
{
    if((obj == _ui.treeView) && (event->type() == QEvent::FocusOut))
    {
        QSettings settings;
        settings.setValue("app/file_browse_last",
                          _model.filePath(_ui.treeView->currentIndex()));
        return false;
    }
    else
    {
        // standard event processing
        return QWidget::eventFilter(obj, event);
    }
}

void FilePickerWidget::updateFilter(QString filter)
{
    _model.setNameFilters(QStringList("*"));
    if(filter.startsWith('/'))
        setCurrentPath(filter);
    else if(!filter.isEmpty())
        _model.setNameFilters(QStringList(filter));
}

void FilePickerWidget::setCurrentPath(const QString path)
{
    _ui.treeView->setCurrentIndex(_model.index(path));
    _ui.treeView->scrollTo(_model.index(path));
}
<commit_msg>FilePickerWidget: Comments and minor reorganization<commit_after>#include "filepickerwidget.h"

#include "debug.h"

#include <QKeyEvent>
#include <QPersistentModelIndex>
#include <QSettings>

FilePickerWidget::FilePickerWidget(QWidget *parent)
    : QWidget(parent)
{
    _ui.setupUi(this);
    _ui.optionsContainer->hide();

    // Configure underlying model.
    _model.setRootPath(QDir::rootPath());

    // Configure file url completions.
    _completer.setModel(&_model);
    _completer.setCompletionMode(QCompleter::InlineCompletion);
    _completer.setCaseSensitivity(Qt::CaseSensitive);
    _ui.filterLineEdit->setCompleter(&_completer);
    _ui.filterLineEdit->setFocus();

    // Configure visual display of the model.
    _ui.treeView->setModel(&_model);
    _ui.treeView->installEventFilter(this);
    _ui.treeView->setColumnWidth(0, 250);

    // Load last browsed file url.
    QSettings settings;
    setCurrentPath(
        settings.value("app/file_browse_last", QDir::homePath()).toString());

    // Connection for the model's data changing.
    connect(&_model, &CustomFileSystemModel::dataChanged,
            [&](const QModelIndex &topLeft, const QModelIndex &bottomRight,
                const QVector<int> &roles) {
                Q_UNUSED(topLeft);
                Q_UNUSED(bottomRight);
                if(!roles.isEmpty() && (roles.first() == SELECTION_CHANGED_ROLE))
                    emit selectionChanged();
            });
    // Connections for the top bar of the widget
    connect(_ui.showOptionsButton, &QPushButton::clicked, [&]() {
        _ui.optionsContainer->setVisible(!_ui.optionsContainer->isVisible());
    });
    connect(_ui.homeButton, &QPushButton::clicked,
            [&]() { setCurrentPath(QDir::homePath()); });
    connect(_ui.filterLineEdit, &QLineEdit::textEdited, this,
            &FilePickerWidget::updateFilter);
    connect(_ui.filterLineEdit, &QLineEdit::returnPressed, [&]() {
        if(_completer.currentCompletion().isEmpty())
            _ui.treeView->setFocus();
    });
    // Connections for the settings
    connect(_ui.showHiddenCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::Hidden);
        else
            _model.setFilter(_model.filter() & ~QDir::Hidden);
        emit settingChanged();
    });
    connect(_ui.showSystemCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::System);
        else
            _model.setFilter(_model.filter() & ~QDir::System);
        emit settingChanged();
    });
    connect(_ui.hideLinksCheckBox, &QCheckBox::toggled, [&](const bool toggled) {
        if(toggled)
            _model.setFilter(_model.filter() | QDir::NoSymLinks);
        else
            _model.setFilter(_model.filter() & ~QDir::NoSymLinks);
        emit settingChanged();
    });
}

FilePickerWidget::~FilePickerWidget()
{
}

void FilePickerWidget::reset()
{
    _model.reset();
    _ui.treeView->reset();
    // Load last browsed file url.
    QSettings settings;
    setCurrentPath(
        settings.value("app/file_browse_last", QDir::homePath()).toString());
}

QList<QUrl> FilePickerWidget::getSelectedUrls()
{
    // Construct a list of urls from the filePath QStrings.
    QList<QUrl> urls;
    QList<QPersistentModelIndex> indexList = _model.checkedIndexes();
    foreach(QPersistentModelIndex index, indexList)
        urls << QUrl::fromUserInput(_model.filePath(index));
    return urls;
}

void FilePickerWidget::setSelectedUrls(const QList<QUrl> &urls)
{
    _model.reset();
    foreach(const QUrl url, urls)
    {
        _model.setData(_model.index(url.toLocalFile()), Qt::Checked,
                       Qt::CheckStateRole);
    }
}

void FilePickerWidget::selectUrl(QUrl url)
{
    _model.setData(_model.index(url.toLocalFile()), Qt::Checked,
                   Qt::CheckStateRole);
}

bool FilePickerWidget::settingShowHidden()
{
    return _ui.showHiddenCheckBox->isChecked();
}

void FilePickerWidget::setSettingShowHidden(bool showHidden)
{
    _ui.showHiddenCheckBox->setChecked(showHidden);
}

bool FilePickerWidget::settingShowSystem()
{
    return _ui.showSystemCheckBox->isChecked();
}

void FilePickerWidget::setSettingShowSystem(bool showSystem)
{
    _ui.showSystemCheckBox->setChecked(showSystem);
}

bool FilePickerWidget::settingHideSymlinks()
{
    return _ui.hideLinksCheckBox->isChecked();
}

void FilePickerWidget::setSettingHideSymlinks(bool hideSymlinks)
{
    _ui.hideLinksCheckBox->setChecked(hideSymlinks);
}

void FilePickerWidget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Escape:
        if(_ui.optionsContainer->isVisible())
        {
            _ui.optionsContainer->hide();
        }
        else if(!_ui.filterLineEdit->hasFocus())
        {
            _ui.filterLineEdit->setFocus();
        }
        else
        {
            QWidget::keyPressEvent(event);
        }
        break;
    default:
        QWidget::keyPressEvent(event);
    }
}

bool FilePickerWidget::eventFilter(QObject *obj, QEvent *event)
{
    if((obj == _ui.treeView) && (event->type() == QEvent::FocusOut))
    {
        // Save last browsed file url.
        QSettings settings;
        settings.setValue("app/file_browse_last",
                          _model.filePath(_ui.treeView->currentIndex()));
        return false;
    }
    else
    {
        // standard event processing
        return QWidget::eventFilter(obj, event);
    }
}

void FilePickerWidget::updateFilter(QString filter)
{
    _model.setNameFilters(QStringList("*"));
    if(filter.startsWith('/'))
        setCurrentPath(filter);
    else if(!filter.isEmpty())
        _model.setNameFilters(QStringList(filter));
}

void FilePickerWidget::setCurrentPath(const QString path)
{
    _ui.treeView->setCurrentIndex(_model.index(path));
    _ui.treeView->scrollTo(_model.index(path));
}
<|endoftext|>


<commit_before>#include "line_shape.hpp"

#include "../drape/utils/vertex_decl.hpp"
#include "../drape/glsl_types.hpp"
#include "../drape/glsl_func.hpp"
#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
#include "../drape/glstate.hpp"
#include "../drape/batcher.hpp"
#include "../drape/texture_manager.hpp"

namespace df
{

namespace
{
  float const SEGMENT = 0.0f;
  float const CAP = 1.0f;
  float const LEFT_WIDTH = 1.0f;
  float const RIGHT_WIDTH = -1.0f;
}

LineShape::LineShape(m2::SharedSpline const & spline,
                     LineViewParams const & params)
  : m_params(params)
  , m_spline(spline)
{
  ASSERT_GREATER(m_spline->GetPath().size(), 1, ());
}

void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureManager> textures) const
{
  buffer_vector<gpu::LineVertex, 128> geometry;
  vector<m2::PointD> const & path = m_spline->GetPath();

  dp::TextureManager::ColorRegion colorRegion;
  textures->GetColorRegion(m_params.m_color, colorRegion);
  glsl::vec2 colorCoord(glsl::ToVec2(colorRegion.GetTexRect().Center()));

  dp::TextureManager::StippleRegion maskRegion;
  textures->GetStippleRegion(dp::TextureManager::TStipplePattern{1}, maskRegion);
  glsl::vec2 maskCoord(glsl::ToVec2(maskRegion.GetTexRect().Center()));

  float const halfWidth = m_params.m_width / 2.0f;
  bool generateCap = m_params.m_cap != dp::ButtCap;

  auto const calcTangentAndNormals = [&halfWidth](glsl::vec2 const & pt0, glsl::vec2 const & pt1,
                                        glsl::vec2 & tangent, glsl::vec2 & leftNormal,
                                        glsl::vec2 & rightNormal)
  {
    tangent = pt1 - pt0;
    leftNormal = halfWidth * glsl::normalize(glsl::vec2(tangent.y, -tangent.x));
    rightNormal = -leftNormal;
  };

  float capType = m_params.m_cap == dp::RoundCap ? CAP : SEGMENT;

  glsl::vec2 leftSegment(SEGMENT, LEFT_WIDTH);
  glsl::vec2 rightSegment(SEGMENT, RIGHT_WIDTH);

  if (generateCap)
  {
    glsl::vec2 startPoint = glsl::ToVec2(path[0]);
    glsl::vec2 endPoint = glsl::ToVec2(path[1]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);
    tangent = -halfWidth * glsl::normalize(tangent);

    glsl::vec3 pivot = glsl::vec3(startPoint, m_params.m_depth);
    glsl::vec2 leftCap(capType, LEFT_WIDTH);
    glsl::vec2 rightCap(capType, RIGHT_WIDTH);

    geometry.push_back(gpu::LineVertex(pivot, leftNormal + tangent, colorCoord, maskCoord, leftCap));
    geometry.push_back(gpu::LineVertex(pivot, rightNormal + tangent, colorCoord, maskCoord, rightCap));
    geometry.push_back(gpu::LineVertex(pivot, leftNormal, colorCoord, maskCoord, leftSegment));
    geometry.push_back(gpu::LineVertex(pivot, rightNormal, colorCoord, maskCoord, rightSegment));
  }

  glsl::vec2 prevPoint;
  glsl::vec2 prevLeftNormal;
  glsl::vec2 prevRightNormal;

  for (size_t i = 1; i < path.size(); ++i)
  {
    glsl::vec2 startPoint = glsl::ToVec2(path[i - 1]);
    glsl::vec2 endPoint = glsl::ToVec2(path[i]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);

    glsl::vec3 startPivot = glsl::vec3(startPoint, m_params.m_depth);
    glsl::vec3 endPivot = glsl::vec3(endPoint, m_params.m_depth);

    // Create join beetween current segment and previous
    if (i > 1)
    {
      glsl::vec2 zeroNormal(0.0, 0.0);
      glsl::vec2 prevForming, nextForming;
      if (glsl::dot(prevLeftNormal, tangent) < 0)
      {
        prevForming = prevLeftNormal;
        nextForming = leftNormal;
      }
      else
      {
        prevForming = prevRightNormal;
        nextForming = rightNormal;
      }

      if (m_params.m_join == dp::BevelJoin)
      {
        geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, leftSegment));
        geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, leftSegment));
        geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, leftSegment));
        geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, leftSegment));
      }
      else
      {
        glsl::vec2 middleForming = glsl::normalize(prevForming + nextForming);
        glsl::vec2 zeroDxDy(0.0, 0.0);

        if (m_params.m_join == dp::MiterJoin)
        {
          float const b = glsl::length(prevForming - nextForming) / 2.0;
          float const a = glsl::length(prevForming);
          middleForming *= static_cast<float>(sqrt(a * a + b * b));

          geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, zeroDxDy));
          geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, zeroDxDy));
          geometry.push_back(gpu::LineVertex(startPivot, middleForming, colorCoord, maskCoord, zeroDxDy));
          geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, zeroDxDy));
        }
        else
        {
          middleForming *= glsl::length(prevForming);

          glsl::vec2 dxdyLeft(0.0, -1.0);
          glsl::vec2 dxdyRight(0.0, -1.0);
          glsl::vec2 dxdyMiddle(1.0, 1.0);
          geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, zeroDxDy));
          geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, dxdyLeft));
          geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, dxdyRight));
          geometry.push_back(gpu::LineVertex(startPivot, middleForming, colorCoord, maskCoord, dxdyMiddle));
        }
      }
    }

    geometry.push_back(gpu::LineVertex(startPivot, leftNormal, colorCoord, maskCoord, leftSegment));
    geometry.push_back(gpu::LineVertex(startPivot, rightNormal, colorCoord, maskCoord, rightSegment));
    geometry.push_back(gpu::LineVertex(endPivot, leftNormal, colorCoord, maskCoord, leftSegment));
    geometry.push_back(gpu::LineVertex(endPivot, rightNormal, colorCoord, maskCoord, rightSegment));

    prevPoint = startPoint;
    prevLeftNormal = leftNormal;
    prevRightNormal = rightNormal;
  }

  if (generateCap)
  {
    size_t lastPointIndex = path.size() - 1;
    glsl::vec2 startPoint = glsl::ToVec2(path[lastPointIndex - 1]);
    glsl::vec2 endPoint = glsl::ToVec2(path[lastPointIndex]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);
    tangent = halfWidth * glsl::normalize(tangent);

    glsl::vec3 pivot = glsl::vec3(endPoint, m_params.m_depth);
    glsl::vec2 leftCap(capType, LEFT_WIDTH);
    glsl::vec2 rightCap(capType, RIGHT_WIDTH);

    geometry.push_back(gpu::LineVertex(pivot, leftNormal, colorCoord, maskCoord, leftSegment));
    geometry.push_back(gpu::LineVertex(pivot, rightNormal, colorCoord, maskCoord, rightSegment));
    geometry.push_back(gpu::LineVertex(pivot, leftNormal + tangent, colorCoord, maskCoord, leftCap));
    geometry.push_back(gpu::LineVertex(pivot, rightNormal + tangent, colorCoord, maskCoord, rightCap));
  }

  dp::GLState state(gpu::LINE_PROGRAM, dp::GLState::GeometryLayer);
  state.SetBlending(true);
  state.SetColorTexture(colorRegion.GetTexture());
  state.SetMaskTexture(maskRegion.GetTexture());

  dp::AttributeProvider provider(1, geometry.size());
  provider.InitStream(0, gpu::LineVertex::GetBindingInfo(), dp::MakeStackRefPointer<void>(geometry.data()));

  batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), 4);
}

} // namespace df

<commit_msg>[drape] texture coord generation for stipple lines<commit_after>#include "line_shape.hpp"

#include "../drape/utils/vertex_decl.hpp"
#include "../drape/glsl_types.hpp"
#include "../drape/glsl_func.hpp"
#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
#include "../drape/glstate.hpp"
#include "../drape/batcher.hpp"
#include "../drape/texture_manager.hpp"

namespace df
{

namespace
{
  float const SEGMENT = 0.0f;
  float const CAP = 1.0f;
  float const LEFT_WIDTH = 1.0f;
  float const RIGHT_WIDTH = -1.0f;
  size_t const TEX_BEG_IDX = 0;
  size_t const TEX_END_IDX = 1;

  struct TexDescription
  {
    float m_globalLength;
    glsl::vec2 m_texCoord;
  };

  class TextureCoordGenerator
  {
  public:
    TextureCoordGenerator(float const baseGtoPScale)
      : m_baseGtoPScale(baseGtoPScale)
      , m_basePtoGScale(1.0f / baseGtoPScale)
    {
    }

    void SetRegion(dp::TextureManager::StippleRegion const & region, bool isSolid)
    {
      m_isSolid = isSolid;
      m_region = region;
      if (!m_isSolid)
      {
        m_maskLength = static_cast<float>(m_region.GetMaskPixelLength());
        m_patternLength = static_cast<float>(m_region.GetPatternPixelLength());
      }
    }

    bool GetTexCoords(TexDescription & desc)
    {
      if (m_isSolid)
      {
        desc.m_texCoord = glsl::ToVec2(m_region.GetTexRect().Center());
        return true;
      }

      float const pxLength = desc.m_globalLength * m_baseGtoPScale;
      float const maskRest = m_maskLength - m_pxCursor;

      m2::RectF const & texRect = m_region.GetTexRect();
      if (maskRest < pxLength)
      {
        desc.m_globalLength = maskRest * m_basePtoGScale;
        desc.m_texCoord = glsl::vec2(texRect.maxX(), texRect.Center().y);
        return false;
      }

      float texX = texRect.minX() + ((m_pxCursor + pxLength) / m_maskLength) * texRect.SizeX();
      m_pxCursor = fmodf(m_pxCursor + pxLength, m_patternLength);

      desc.m_texCoord = glsl::vec2(texX, texRect.Center().y);
      return true;
    }

  private:
    float const m_baseGtoPScale;
    float const m_basePtoGScale;
    dp::TextureManager::StippleRegion m_region;
    float m_maskLength = 0.0f;
    float m_patternLength = 0.0f;
    bool m_isSolid = true;
    float m_pxCursor = 0.0f;
  };
}

LineShape::LineShape(m2::SharedSpline const & spline,
                     LineViewParams const & params)
  : m_params(params)
  , m_spline(spline)
{
  ASSERT_GREATER(m_spline->GetPath().size(), 1, ());
}

void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureManager> textures) const
{
  typedef gpu::LineVertex LV;
  buffer_vector<gpu::LineVertex, 128> geometry;
  vector<m2::PointD> const & path = m_spline->GetPath();

  dp::TextureManager::ColorRegion colorRegion;
  textures->GetColorRegion(m_params.m_color, colorRegion);
  glsl::vec2 colorCoord(glsl::ToVec2(colorRegion.GetTexRect().Center()));

  TextureCoordGenerator texCoordGen(m_params.m_baseGtoPScale);
  dp::TextureManager::StippleRegion maskRegion;
  if (m_params.m_pattern.empty())
    textures->GetStippleRegion(dp::TextureManager::TStipplePattern{1}, maskRegion);
  else
    textures->GetStippleRegion(m_params.m_pattern, maskRegion);

  texCoordGen.SetRegion(maskRegion, m_params.m_pattern.empty());
  float const halfWidth = m_params.m_width / 2.0f;
  float const glbHalfWidth = halfWidth / m_params.m_baseGtoPScale;
  bool generateCap = m_params.m_cap != dp::ButtCap;

  auto const calcTangentAndNormals = [&halfWidth](glsl::vec2 const & pt0, glsl::vec2 const & pt1,
                                        glsl::vec2 & tangent, glsl::vec2 & leftNormal,
                                        glsl::vec2 & rightNormal)
  {
    tangent = glsl::normalize(pt1 - pt0);
    leftNormal = halfWidth * glsl::vec2(tangent.y, -tangent.x);
    rightNormal = -leftNormal;
  };

  float capType = m_params.m_cap == dp::RoundCap ? CAP : SEGMENT;

  glsl::vec2 leftSegment(SEGMENT, LEFT_WIDTH);
  glsl::vec2 rightSegment(SEGMENT, RIGHT_WIDTH);

  TexDescription texCoords[2];

  if (generateCap)
  {
    glsl::vec2 startPoint = glsl::ToVec2(path[0]);
    glsl::vec2 endPoint = glsl::ToVec2(path[1]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);
    tangent = -halfWidth * tangent;

    glsl::vec3 pivot = glsl::vec3(startPoint, m_params.m_depth);
    glsl::vec2 leftCap(capType, LEFT_WIDTH);
    glsl::vec2 rightCap(capType, RIGHT_WIDTH);

    texCoords[TEX_BEG_IDX].m_globalLength = 0.0;
    texCoords[TEX_END_IDX].m_globalLength = glbHalfWidth;

    VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
    VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ());

    geometry.push_back(LV(pivot, leftNormal + tangent, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftCap));
    geometry.push_back(LV(pivot, rightNormal + tangent, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightCap));
    geometry.push_back(LV(pivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment));
    geometry.push_back(LV(pivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment));
  }

  glsl::vec2 prevPoint;
  glsl::vec2 prevLeftNormal;
  glsl::vec2 prevRightNormal;

  for (size_t i = 1; i < path.size(); ++i)
  {
    glsl::vec2 startPoint = glsl::ToVec2(path[i - 1]);
    glsl::vec2 endPoint = glsl::ToVec2(path[i]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);

    glsl::vec3 startPivot = glsl::vec3(startPoint, m_params.m_depth);
    glsl::vec3 endPivot = glsl::vec3(endPoint, m_params.m_depth);

    // Create join beetween current segment and previous
    if (i > 1)
    {
      glsl::vec2 zeroNormal(0.0, 0.0);
      glsl::vec2 prevForming, nextForming;
      if (glsl::dot(prevLeftNormal, tangent) < 0)
      {
        prevForming = prevLeftNormal;
        nextForming = leftNormal;
      }
      else
      {
        prevForming = prevRightNormal;
        nextForming = rightNormal;
      }

      if (m_params.m_join == dp::BevelJoin)
      {
        texCoords[TEX_BEG_IDX].m_globalLength = 0.0f;
        texCoords[TEX_END_IDX].m_globalLength = glsl::length(nextForming - prevForming) / m_params.m_baseGtoPScale;
        VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
        VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ());

        geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment));
        geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment));
        geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment));
        geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment));
      }
      else
      {
        glsl::vec2 middleForming = glsl::normalize(prevForming + nextForming);
        glsl::vec2 zeroDxDy(0.0, 0.0);

        texCoords[TEX_BEG_IDX].m_globalLength = 0.0f;
        texCoords[TEX_END_IDX].m_globalLength = glsl::length(nextForming - prevForming) / m_params.m_baseGtoPScale;
        TexDescription middle;
        middle.m_globalLength = texCoords[TEX_END_IDX].m_globalLength / 2.0f;
        VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
        VERIFY(texCoordGen.GetTexCoords(middle), ());
        VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ());

        if (m_params.m_join == dp::MiterJoin)
        {
          float const b = glsl::length(prevForming - nextForming) / 2.0;
          float const a = glsl::length(prevForming);
          middleForming *= static_cast<float>(sqrt(a * a + b * b));

          geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy));
          geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy));
          geometry.push_back(LV(startPivot, middleForming, colorCoord, middle.m_texCoord, zeroDxDy));
          geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, zeroDxDy));
        }
        else
        {
          middleForming *= glsl::length(prevForming);

          glsl::vec2 dxdyLeft(0.0, -1.0);
          glsl::vec2 dxdyRight(0.0, -1.0);
          glsl::vec2 dxdyMiddle(1.0, 1.0);
          geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy));
          geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, dxdyLeft));
          geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, dxdyRight));
          geometry.push_back(LV(startPivot, middleForming, colorCoord, middle.m_texCoord, dxdyMiddle));
        }
      }
    }

    texCoords[TEX_BEG_IDX].m_globalLength = 0.0;
    texCoords[TEX_END_IDX].m_globalLength = glsl::length(endPoint - startPoint);
    VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
    while (!texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]))
    {
      glsl::vec2 newEndPoint = startPoint + tangent * texCoords[TEX_END_IDX].m_globalLength;
      glsl::vec3 newEndPivot = glsl::vec3(newEndPoint, m_params.m_depth);

      geometry.push_back(LV(startPivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment));
      geometry.push_back(LV(startPivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment));
      geometry.push_back(LV(newEndPivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment));
      geometry.push_back(LV(newEndPivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment));

      startPoint = newEndPoint;
      startPivot = newEndPivot;

      VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
      texCoords[TEX_END_IDX].m_globalLength = glsl::length(endPoint - startPoint);
    }

    geometry.push_back(LV(startPivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment));
    geometry.push_back(LV(startPivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment));
    geometry.push_back(LV(endPivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment));
    geometry.push_back(LV(endPivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment));

    prevPoint = startPoint;
    prevLeftNormal = leftNormal;
    prevRightNormal = rightNormal;
  }

  if (generateCap)
  {
    size_t lastPointIndex = path.size() - 1;
    glsl::vec2 startPoint = glsl::ToVec2(path[lastPointIndex - 1]);
    glsl::vec2 endPoint = glsl::ToVec2(path[lastPointIndex]);
    glsl::vec2 tangent, leftNormal, rightNormal;
    calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal);
    tangent = halfWidth * tangent;

    glsl::vec3 pivot = glsl::vec3(endPoint, m_params.m_depth);
    glsl::vec2 leftCap(capType, LEFT_WIDTH);
    glsl::vec2 rightCap(capType, RIGHT_WIDTH);

    texCoords[TEX_BEG_IDX].m_globalLength = 0.0;
    texCoords[TEX_END_IDX].m_globalLength = glbHalfWidth;

    VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ());
    VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ());

    geometry.push_back(LV(pivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment));
    geometry.push_back(LV(pivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment));
    geometry.push_back(LV(pivot, leftNormal + tangent, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftCap));
    geometry.push_back(LV(pivot, rightNormal + tangent, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightCap));
  }

  dp::GLState state(gpu::LINE_PROGRAM, dp::GLState::GeometryLayer);
  state.SetBlending(true);
  state.SetColorTexture(colorRegion.GetTexture());
  state.SetMaskTexture(maskRegion.GetTexture());

  dp::AttributeProvider provider(1, geometry.size());
  provider.InitStream(0, gpu::LineVertex::GetBindingInfo(), dp::MakeStackRefPointer<void>(geometry.data()));

  batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), 4);
}

} // namespace df

<|endoftext|>


<commit_before><commit_msg>Reuse UseReferenceBuild() cleanup in startup test.<commit_after><|endoftext|>


<commit_before>/// Project-level integration tests
#include "stdafx.h"
#include <CppUnitTest.h>

using Assert = Microsoft::VisualStudio::CppUnitTestFramework::Assert;

namespace You {
namespace NLP {
namespace Tests {
	TEST_CLASS(NlpTests) {
	public:
		TEST_METHOD(DummyTest1) {
			Assert::IsTrue(true);
		}
	};
}  // namespace Tests
}  // namespace NLP
}  // namespace You
<commit_msg>Remove dummy test.<commit_after>/// Project-level integration tests
#include "stdafx.h"
#include <CppUnitTest.h>

using Assert = Microsoft::VisualStudio::CppUnitTestFramework::Assert;

namespace You {
namespace NLP {
namespace Tests {

TEST_CLASS(NlpTests) {
public:
};

}  // namespace Tests
}  // namespace NLP
}  // namespace You
<|endoftext|>