<commit_before>//===-- HexagonISelLoweringHVX.cpp --- Lowering HVX operations ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "HexagonISelLowering.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"

using namespace llvm;

SDValue
HexagonTargetLowering::getInt(unsigned IntId, MVT ResTy, ArrayRef<SDValue> Ops,
                              const SDLoc &dl, SelectionDAG &DAG) const {
  SmallVector<SDValue,4> IntOps;
  IntOps.push_back(DAG.getConstant(IntId, dl, MVT::i32));
  for (const SDValue &Op : Ops)
    IntOps.push_back(Op);
  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ResTy, IntOps);
}

MVT
HexagonTargetLowering::typeJoin(const TypePair &Tys) const {
  assert(Tys.first.getVectorElementType() == Tys.second.getVectorElementType());

  MVT ElemTy = Tys.first.getVectorElementType();
  return MVT::getVectorVT(ElemTy, Tys.first.getVectorNumElements() +
                                  Tys.second.getVectorNumElements());
}

HexagonTargetLowering::TypePair
HexagonTargetLowering::typeSplit(MVT VecTy) const {
  assert(VecTy.isVector());
  unsigned NumElem = VecTy.getVectorNumElements();
  assert((NumElem % 2) == 0 && "Expecting even-sized vector type");
  MVT HalfTy = MVT::getVectorVT(VecTy.getVectorElementType(), NumElem/2);
  return { HalfTy, HalfTy };
}

MVT
HexagonTargetLowering::typeExtElem(MVT VecTy, unsigned Factor) const {
  MVT ElemTy = VecTy.getVectorElementType();
  MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() * Factor);
  return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
}

MVT
HexagonTargetLowering::typeTruncElem(MVT VecTy, unsigned Factor) const {
  MVT ElemTy = VecTy.getVectorElementType();
  MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() / Factor);
  return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
}

SDValue
HexagonTargetLowering::opCastElem(SDValue Vec, MVT ElemTy,
                                  SelectionDAG &DAG) const {
  if (ty(Vec).getVectorElementType() == ElemTy)
    return Vec;
  MVT CastTy = tyVector(Vec.getValueType().getSimpleVT(), ElemTy);
  return DAG.getBitcast(CastTy, Vec);
}

SDValue
HexagonTargetLowering::opJoin(const VectorPair &Ops, const SDLoc &dl,
                              SelectionDAG &DAG) const {
  return DAG.getNode(ISD::CONCAT_VECTORS, dl, typeJoin(ty(Ops)),
                     Ops.second, Ops.first);
}

HexagonTargetLowering::VectorPair
HexagonTargetLowering::opSplit(SDValue Vec, const SDLoc &dl,
                               SelectionDAG &DAG) const {
  TypePair Tys = typeSplit(ty(Vec));
  return DAG.SplitVector(Vec, dl, Tys.first, Tys.second);
}

SDValue
HexagonTargetLowering::convertToByteIndex(SDValue ElemIdx, MVT ElemTy,
                                          SelectionDAG &DAG) const {
  if (ElemIdx.getValueType().getSimpleVT() != MVT::i32)
    ElemIdx = DAG.getBitcast(MVT::i32, ElemIdx);

  unsigned ElemWidth = ElemTy.getSizeInBits();
  if (ElemWidth == 8)
    return ElemIdx;

  unsigned L = Log2_32(ElemWidth/8);
  const SDLoc &dl(ElemIdx);
  return DAG.getNode(ISD::SHL, dl, MVT::i32,
                     {ElemIdx, DAG.getConstant(L, dl, MVT::i32)});
}

SDValue
HexagonTargetLowering::getIndexInWord32(SDValue Idx, MVT ElemTy,
                                        SelectionDAG &DAG) const {
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32);
  if (ElemWidth == 32)
    return Idx;

  if (ty(Idx) != MVT::i32)
    Idx = DAG.getBitcast(MVT::i32, Idx);
  const SDLoc &dl(Idx);
  SDValue Mask = DAG.getConstant(32/ElemWidth - 1, dl, MVT::i32);
  SDValue SubIdx = DAG.getNode(ISD::AND, dl, MVT::i32, {Idx, Mask});
  return SubIdx;
}

SDValue
HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
      const {
  const SDLoc &dl(Op);
  BuildVectorSDNode *BN = cast<BuildVectorSDNode>(Op.getNode());
  bool IsConst = BN->isConstant();
  MachineFunction &MF = DAG.getMachineFunction();
  MVT VecTy = ty(Op);

  if (IsConst) {
    SmallVector<Constant*, 128> Elems;
    for (SDValue V : BN->op_values()) {
      if (auto *C = dyn_cast<ConstantSDNode>(V.getNode()))
        Elems.push_back(const_cast<ConstantInt*>(C->getConstantIntValue()));
    }
    Constant *CV = ConstantVector::get(Elems);
    unsigned Align = VecTy.getSizeInBits() / 8;
    SDValue CP = LowerConstantPool(DAG.getConstantPool(CV, VecTy, Align), DAG);
    return DAG.getLoad(VecTy, dl, DAG.getEntryNode(), CP,
                       MachinePointerInfo::getConstantPool(MF), Align);
  }

  unsigned NumOps = Op.getNumOperands();
  unsigned HwLen = Subtarget.getVectorLength();
  unsigned ElemSize = VecTy.getVectorElementType().getSizeInBits() / 8;
  assert(ElemSize*NumOps == HwLen);

  SmallVector<SDValue,32> Words;
  SmallVector<SDValue,32> Ops;
  for (unsigned i = 0; i != NumOps; ++i)
    Ops.push_back(Op.getOperand(i));

  if (VecTy.getVectorElementType() != MVT::i32) {
    assert(ElemSize < 4 && "vNi64 should have been promoted to vNi32");
    assert((ElemSize == 1 || ElemSize == 2) && "Invalid element size");
    unsigned OpsPerWord = (ElemSize == 1) ? 4 : 2;
    MVT PartVT = MVT::getVectorVT(VecTy.getVectorElementType(), OpsPerWord);
    for (unsigned i = 0; i != NumOps; i += OpsPerWord) {
      SDValue W = buildVector32({&Ops[i], OpsPerWord}, dl, PartVT, DAG);
      Words.push_back(DAG.getBitcast(MVT::i32, W));
    }
  } else {
    Words.assign(Ops.begin(), Ops.end());
  }

  // Construct two halves in parallel, then or them together.
  assert(4*Words.size() == Subtarget.getVectorLength());
  SDValue HalfV0 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG);
  SDValue HalfV1 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG);
  SDValue S = DAG.getConstant(4, dl, MVT::i32);
  unsigned NumWords = Words.size();
  for (unsigned i = 0; i != NumWords/2; ++i) {
    SDValue N = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
                            {HalfV0, Words[i]});
    SDValue M = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
                            {HalfV1, Words[i+NumWords/2]});
    HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, S});
    HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, S});
  }

  HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy,
                       {HalfV0, DAG.getConstant(HwLen/2, dl, MVT::i32)});
  SDValue DstV = DAG.getNode(ISD::OR, dl, VecTy, {HalfV0, HalfV1});
  return DstV;
}

SDValue
HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG)
      const {
  // Change the type of the extracted element to i32.
  SDValue VecV = Op.getOperand(0);
  MVT ElemTy = ty(VecV).getVectorElementType();
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64

  const SDLoc &dl(Op);
  SDValue IdxV = Op.getOperand(1);
  if (ty(IdxV) != MVT::i32)
    IdxV = DAG.getBitcast(MVT::i32, IdxV);

  SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
  SDValue ExWord = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
                               {VecV, ByteIdx});
  if (ElemTy == MVT::i32)
    return ExWord;

  // Have an extracted word, need to extract the smaller element out of it.
  // 1. Extract the bits of (the original) IdxV that correspond to the index
  //    of the desired element in the 32-bit word.
  SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
  // 2. Extract the element from the word.
  SDValue ExVec = DAG.getBitcast(tyVector(ty(ExWord), ElemTy), ExWord);
  return extractVector(ExVec, SubIdx, dl, ElemTy, MVT::i32, DAG);
}

SDValue
HexagonTargetLowering::LowerHvxInsertElement(SDValue Op, SelectionDAG &DAG)
      const {
  const SDLoc &dl(Op);
  SDValue VecV = Op.getOperand(0);
  SDValue ValV = Op.getOperand(1);
  SDValue IdxV = Op.getOperand(2);
  MVT ElemTy = ty(VecV).getVectorElementType();
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64

  auto InsertWord = [&DAG,&dl,this] (SDValue VecV, SDValue ValV,
                                     SDValue ByteIdxV) {
    MVT VecTy = ty(VecV);
    unsigned HwLen = Subtarget.getVectorLength();
    SDValue MaskV = DAG.getNode(ISD::AND, dl, MVT::i32,
                                {ByteIdxV, DAG.getConstant(-4, dl, MVT::i32)});
    SDValue RotV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {VecV, MaskV});
    SDValue InsV = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, {RotV, ValV});
    SDValue SubV = DAG.getNode(ISD::SUB, dl, MVT::i32,
                               {DAG.getConstant(HwLen/4, dl, MVT::i32), MaskV});
    SDValue TorV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {InsV, SubV});
    return TorV;
  };

  SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
  if (ElemTy == MVT::i32)
    return InsertWord(VecV, ValV, ByteIdx);

  // If this is not inserting a 32-bit word, convert it into such a thing.
  // 1. Extract the existing word from the target vector.
  SDValue WordIdx = DAG.getNode(ISD::SRL, dl, MVT::i32,
                                {ByteIdx, DAG.getConstant(2, dl, MVT::i32)});
  SDValue Ex0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32,
                            {opCastElem(VecV, MVT::i32, DAG), WordIdx});
  SDValue Ext = LowerHvxExtractElement(Ex0, DAG);

  // 2. Treating the extracted word as a 32-bit vector, insert the given
  //    value into it.
  SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
  MVT SubVecTy = tyVector(ty(Ext), ElemTy);
  SDValue Ins = insertVector(DAG.getBitcast(SubVecTy, Ext),
                             ValV, SubIdx, dl, SubVecTy, DAG);

  // 3. Insert the 32-bit word back into the original vector.
  return InsertWord(VecV, Ins, ByteIdx);
}

SDValue
HexagonTargetLowering::LowerHvxExtractSubvector(SDValue Op, SelectionDAG &DAG)
      const {
  SDValue SrcV = Op.getOperand(0);
  MVT SrcTy = ty(SrcV);
  unsigned SrcElems = SrcTy.getVectorNumElements();
  SDValue IdxV = Op.getOperand(1);
  unsigned Idx = cast<ConstantSDNode>(IdxV.getNode())->getZExtValue();
  MVT DstTy = ty(Op);
  assert(Idx == 0 || DstTy.getVectorNumElements() % Idx == 0);
  const SDLoc &dl(Op);
  if (Idx == 0)
    return DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, DstTy, SrcV);
  if (Idx == SrcElems/2)
    return DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, DstTy, SrcV);
  return SDValue();
}

SDValue
HexagonTargetLowering::LowerHvxInsertSubvector(SDValue Op, SelectionDAG &DAG)
      const {
  // Idx may be variable
  SDValue IdxV = Op.getOperand(2);
  auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
  if (!IdxN)
    return SDValue();
  unsigned Idx = IdxN->getZExtValue();

  SDValue DstV = Op.getOperand(0);
  SDValue SrcV = Op.getOperand(1);
  MVT DstTy = ty(DstV);
  MVT SrcTy = ty(SrcV);
  unsigned DstElems = DstTy.getVectorNumElements();
  unsigned SrcElems = SrcTy.getVectorNumElements();
  if (2*SrcElems != DstElems)
    return SDValue();

  const SDLoc &dl(Op);
  if (Idx == 0)
    return DAG.getTargetInsertSubreg(Hexagon::vsub_lo, dl, DstTy, DstV, SrcV);
  if (Idx == SrcElems)
    return DAG.getTargetInsertSubreg(Hexagon::vsub_hi, dl, DstTy, DstV, SrcV);
  return SDValue();
}
<commit_msg>[Hexagon] Suppress warnings on unused variables defind for asserts.<commit_after>//===-- HexagonISelLoweringHVX.cpp --- Lowering HVX operations ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "HexagonISelLowering.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"

using namespace llvm;

SDValue
HexagonTargetLowering::getInt(unsigned IntId, MVT ResTy, ArrayRef<SDValue> Ops,
                              const SDLoc &dl, SelectionDAG &DAG) const {
  SmallVector<SDValue,4> IntOps;
  IntOps.push_back(DAG.getConstant(IntId, dl, MVT::i32));
  for (const SDValue &Op : Ops)
    IntOps.push_back(Op);
  return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ResTy, IntOps);
}

MVT
HexagonTargetLowering::typeJoin(const TypePair &Tys) const {
  assert(Tys.first.getVectorElementType() == Tys.second.getVectorElementType());

  MVT ElemTy = Tys.first.getVectorElementType();
  return MVT::getVectorVT(ElemTy, Tys.first.getVectorNumElements() +
                                  Tys.second.getVectorNumElements());
}

HexagonTargetLowering::TypePair
HexagonTargetLowering::typeSplit(MVT VecTy) const {
  assert(VecTy.isVector());
  unsigned NumElem = VecTy.getVectorNumElements();
  assert((NumElem % 2) == 0 && "Expecting even-sized vector type");
  MVT HalfTy = MVT::getVectorVT(VecTy.getVectorElementType(), NumElem/2);
  return { HalfTy, HalfTy };
}

MVT
HexagonTargetLowering::typeExtElem(MVT VecTy, unsigned Factor) const {
  MVT ElemTy = VecTy.getVectorElementType();
  MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() * Factor);
  return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
}

MVT
HexagonTargetLowering::typeTruncElem(MVT VecTy, unsigned Factor) const {
  MVT ElemTy = VecTy.getVectorElementType();
  MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() / Factor);
  return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
}

SDValue
HexagonTargetLowering::opCastElem(SDValue Vec, MVT ElemTy,
                                  SelectionDAG &DAG) const {
  if (ty(Vec).getVectorElementType() == ElemTy)
    return Vec;
  MVT CastTy = tyVector(Vec.getValueType().getSimpleVT(), ElemTy);
  return DAG.getBitcast(CastTy, Vec);
}

SDValue
HexagonTargetLowering::opJoin(const VectorPair &Ops, const SDLoc &dl,
                              SelectionDAG &DAG) const {
  return DAG.getNode(ISD::CONCAT_VECTORS, dl, typeJoin(ty(Ops)),
                     Ops.second, Ops.first);
}

HexagonTargetLowering::VectorPair
HexagonTargetLowering::opSplit(SDValue Vec, const SDLoc &dl,
                               SelectionDAG &DAG) const {
  TypePair Tys = typeSplit(ty(Vec));
  return DAG.SplitVector(Vec, dl, Tys.first, Tys.second);
}

SDValue
HexagonTargetLowering::convertToByteIndex(SDValue ElemIdx, MVT ElemTy,
                                          SelectionDAG &DAG) const {
  if (ElemIdx.getValueType().getSimpleVT() != MVT::i32)
    ElemIdx = DAG.getBitcast(MVT::i32, ElemIdx);

  unsigned ElemWidth = ElemTy.getSizeInBits();
  if (ElemWidth == 8)
    return ElemIdx;

  unsigned L = Log2_32(ElemWidth/8);
  const SDLoc &dl(ElemIdx);
  return DAG.getNode(ISD::SHL, dl, MVT::i32,
                     {ElemIdx, DAG.getConstant(L, dl, MVT::i32)});
}

SDValue
HexagonTargetLowering::getIndexInWord32(SDValue Idx, MVT ElemTy,
                                        SelectionDAG &DAG) const {
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32);
  if (ElemWidth == 32)
    return Idx;

  if (ty(Idx) != MVT::i32)
    Idx = DAG.getBitcast(MVT::i32, Idx);
  const SDLoc &dl(Idx);
  SDValue Mask = DAG.getConstant(32/ElemWidth - 1, dl, MVT::i32);
  SDValue SubIdx = DAG.getNode(ISD::AND, dl, MVT::i32, {Idx, Mask});
  return SubIdx;
}

SDValue
HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
      const {
  const SDLoc &dl(Op);
  BuildVectorSDNode *BN = cast<BuildVectorSDNode>(Op.getNode());
  bool IsConst = BN->isConstant();
  MachineFunction &MF = DAG.getMachineFunction();
  MVT VecTy = ty(Op);

  if (IsConst) {
    SmallVector<Constant*, 128> Elems;
    for (SDValue V : BN->op_values()) {
      if (auto *C = dyn_cast<ConstantSDNode>(V.getNode()))
        Elems.push_back(const_cast<ConstantInt*>(C->getConstantIntValue()));
    }
    Constant *CV = ConstantVector::get(Elems);
    unsigned Align = VecTy.getSizeInBits() / 8;
    SDValue CP = LowerConstantPool(DAG.getConstantPool(CV, VecTy, Align), DAG);
    return DAG.getLoad(VecTy, dl, DAG.getEntryNode(), CP,
                       MachinePointerInfo::getConstantPool(MF), Align);
  }

  unsigned NumOps = Op.getNumOperands();
  unsigned HwLen = Subtarget.getVectorLength();
  unsigned ElemSize = VecTy.getVectorElementType().getSizeInBits() / 8;
  assert(ElemSize*NumOps == HwLen);

  SmallVector<SDValue,32> Words;
  SmallVector<SDValue,32> Ops;
  for (unsigned i = 0; i != NumOps; ++i)
    Ops.push_back(Op.getOperand(i));

  if (VecTy.getVectorElementType() != MVT::i32) {
    assert(ElemSize < 4 && "vNi64 should have been promoted to vNi32");
    assert((ElemSize == 1 || ElemSize == 2) && "Invalid element size");
    unsigned OpsPerWord = (ElemSize == 1) ? 4 : 2;
    MVT PartVT = MVT::getVectorVT(VecTy.getVectorElementType(), OpsPerWord);
    for (unsigned i = 0; i != NumOps; i += OpsPerWord) {
      SDValue W = buildVector32({&Ops[i], OpsPerWord}, dl, PartVT, DAG);
      Words.push_back(DAG.getBitcast(MVT::i32, W));
    }
  } else {
    Words.assign(Ops.begin(), Ops.end());
  }

  // Construct two halves in parallel, then or them together.
  assert(4*Words.size() == Subtarget.getVectorLength());
  SDValue HalfV0 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG);
  SDValue HalfV1 = getNode(Hexagon::V6_vd0, dl, VecTy, {}, DAG);
  SDValue S = DAG.getConstant(4, dl, MVT::i32);
  unsigned NumWords = Words.size();
  for (unsigned i = 0; i != NumWords/2; ++i) {
    SDValue N = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
                            {HalfV0, Words[i]});
    SDValue M = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
                            {HalfV1, Words[i+NumWords/2]});
    HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, S});
    HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, S});
  }

  HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy,
                       {HalfV0, DAG.getConstant(HwLen/2, dl, MVT::i32)});
  SDValue DstV = DAG.getNode(ISD::OR, dl, VecTy, {HalfV0, HalfV1});
  return DstV;
}

SDValue
HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG)
      const {
  // Change the type of the extracted element to i32.
  SDValue VecV = Op.getOperand(0);
  MVT ElemTy = ty(VecV).getVectorElementType();
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64
  (void)ElemWidth;

  const SDLoc &dl(Op);
  SDValue IdxV = Op.getOperand(1);
  if (ty(IdxV) != MVT::i32)
    IdxV = DAG.getBitcast(MVT::i32, IdxV);

  SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
  SDValue ExWord = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
                               {VecV, ByteIdx});
  if (ElemTy == MVT::i32)
    return ExWord;

  // Have an extracted word, need to extract the smaller element out of it.
  // 1. Extract the bits of (the original) IdxV that correspond to the index
  //    of the desired element in the 32-bit word.
  SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
  // 2. Extract the element from the word.
  SDValue ExVec = DAG.getBitcast(tyVector(ty(ExWord), ElemTy), ExWord);
  return extractVector(ExVec, SubIdx, dl, ElemTy, MVT::i32, DAG);
}

SDValue
HexagonTargetLowering::LowerHvxInsertElement(SDValue Op, SelectionDAG &DAG)
      const {
  const SDLoc &dl(Op);
  SDValue VecV = Op.getOperand(0);
  SDValue ValV = Op.getOperand(1);
  SDValue IdxV = Op.getOperand(2);
  MVT ElemTy = ty(VecV).getVectorElementType();
  unsigned ElemWidth = ElemTy.getSizeInBits();
  assert(ElemWidth >= 8 && ElemWidth <= 32); // TODO i64
  (void)ElemWidth;

  auto InsertWord = [&DAG,&dl,this] (SDValue VecV, SDValue ValV,
                                     SDValue ByteIdxV) {
    MVT VecTy = ty(VecV);
    unsigned HwLen = Subtarget.getVectorLength();
    SDValue MaskV = DAG.getNode(ISD::AND, dl, MVT::i32,
                                {ByteIdxV, DAG.getConstant(-4, dl, MVT::i32)});
    SDValue RotV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {VecV, MaskV});
    SDValue InsV = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, {RotV, ValV});
    SDValue SubV = DAG.getNode(ISD::SUB, dl, MVT::i32,
                               {DAG.getConstant(HwLen/4, dl, MVT::i32), MaskV});
    SDValue TorV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {InsV, SubV});
    return TorV;
  };

  SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
  if (ElemTy == MVT::i32)
    return InsertWord(VecV, ValV, ByteIdx);

  // If this is not inserting a 32-bit word, convert it into such a thing.
  // 1. Extract the existing word from the target vector.
  SDValue WordIdx = DAG.getNode(ISD::SRL, dl, MVT::i32,
                                {ByteIdx, DAG.getConstant(2, dl, MVT::i32)});
  SDValue Ex0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32,
                            {opCastElem(VecV, MVT::i32, DAG), WordIdx});
  SDValue Ext = LowerHvxExtractElement(Ex0, DAG);

  // 2. Treating the extracted word as a 32-bit vector, insert the given
  //    value into it.
  SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
  MVT SubVecTy = tyVector(ty(Ext), ElemTy);
  SDValue Ins = insertVector(DAG.getBitcast(SubVecTy, Ext),
                             ValV, SubIdx, dl, SubVecTy, DAG);

  // 3. Insert the 32-bit word back into the original vector.
  return InsertWord(VecV, Ins, ByteIdx);
}

SDValue
HexagonTargetLowering::LowerHvxExtractSubvector(SDValue Op, SelectionDAG &DAG)
      const {
  SDValue SrcV = Op.getOperand(0);
  MVT SrcTy = ty(SrcV);
  unsigned SrcElems = SrcTy.getVectorNumElements();
  SDValue IdxV = Op.getOperand(1);
  unsigned Idx = cast<ConstantSDNode>(IdxV.getNode())->getZExtValue();
  MVT DstTy = ty(Op);
  assert(Idx == 0 || DstTy.getVectorNumElements() % Idx == 0);
  const SDLoc &dl(Op);
  if (Idx == 0)
    return DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, DstTy, SrcV);
  if (Idx == SrcElems/2)
    return DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, DstTy, SrcV);
  return SDValue();
}

SDValue
HexagonTargetLowering::LowerHvxInsertSubvector(SDValue Op, SelectionDAG &DAG)
      const {
  // Idx may be variable
  SDValue IdxV = Op.getOperand(2);
  auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
  if (!IdxN)
    return SDValue();
  unsigned Idx = IdxN->getZExtValue();

  SDValue DstV = Op.getOperand(0);
  SDValue SrcV = Op.getOperand(1);
  MVT DstTy = ty(DstV);
  MVT SrcTy = ty(SrcV);
  unsigned DstElems = DstTy.getVectorNumElements();
  unsigned SrcElems = SrcTy.getVectorNumElements();
  if (2*SrcElems != DstElems)
    return SDValue();

  const SDLoc &dl(Op);
  if (Idx == 0)
    return DAG.getTargetInsertSubreg(Hexagon::vsub_lo, dl, DstTy, DstV, SrcV);
  if (Idx == SrcElems)
    return DAG.getTargetInsertSubreg(Hexagon::vsub_hi, dl, DstTy, DstV, SrcV);
  return SDValue();
}
<|endoftext|>


<commit_before>#include "GUI_Utils.hpp"

#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

#ifdef _WIN32
#include <Windows.h>
#endif

#include <wx/toplevel.h>
#include <wx/sizer.h>
#include <wx/checkbox.h>
#include <wx/dcclient.h>
#include <wx/font.h>
#include <wx/fontutil.h>

#include "libslic3r/Config.hpp"

namespace Slic3r {
namespace GUI {

wxTopLevelWindow* find_toplevel_parent(wxWindow *window)
{
    for (; window != nullptr; window = window->GetParent()) {
        if (window->IsTopLevel()) {
            return dynamic_cast<wxTopLevelWindow*>(window);
        }
    }

    return nullptr;
}

void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback)
{
#ifdef _WIN32
    // On windows, the wxEVT_SHOW is not received if the window is created maximized
    // cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI
    // OTOH the geometry is available very soon, so we can call the callback right away
    callback();
#elif defined __linux__
    tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) {
        // On Linux, the geometry is only available after wxEVT_SHOW + CallAfter
        // cf. https://groups.google.com/forum/?pli=1#!topic/wx-users/fERSXdpVwAI
        tlw->CallAfter([=]() { callback(); });
        evt.Skip();
    });
#elif defined __APPLE__
    tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) {
        callback();
        evt.Skip();
    });
#endif
}

wxDEFINE_EVENT(EVT_DPI_CHANGED_SLICER, DpiChangedEvent);

#ifdef _WIN32
template<class F> typename F::FN winapi_get_function(const wchar_t *dll, const char *fn_name) {
    static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0);

    if (dll_handle == nullptr) { return nullptr; }
    return (typename F::FN)GetProcAddress(dll_handle, fn_name);
}
#endif

// If called with nullptr, a DPI for the primary monitor is returned.
int get_dpi_for_window(wxWindow *window)
{
#ifdef _WIN32
    enum MONITOR_DPI_TYPE_ {
        // This enum is inlined here to avoid build-time dependency
        MDT_EFFECTIVE_DPI_ = 0,
        MDT_ANGULAR_DPI_ = 1,
        MDT_RAW_DPI_ = 2,
        MDT_DEFAULT_ = MDT_EFFECTIVE_DPI_,
    };

    // Need strong types for winapi_get_function() to work
    struct GetDpiForWindow_t { typedef HRESULT (WINAPI *FN)(HWND hwnd); };
    struct GetDpiForMonitor_t { typedef HRESULT (WINAPI *FN)(HMONITOR hmonitor, MONITOR_DPI_TYPE_ dpiType, UINT *dpiX, UINT *dpiY); };

    static auto GetDpiForWindow_fn = winapi_get_function<GetDpiForWindow_t>(L"User32.dll", "GetDpiForWindow");
    static auto GetDpiForMonitor_fn = winapi_get_function<GetDpiForMonitor_t>(L"Shcore.dll", "GetDpiForMonitor");

	// Desktop Window is the window of the primary monitor.
	const HWND hwnd = (window == nullptr) ? ::GetDesktopWindow() : window->GetHandle();

    if (GetDpiForWindow_fn != nullptr) {
        // We're on Windows 10, we have per-screen DPI settings
        return GetDpiForWindow_fn(hwnd);
    } else if (GetDpiForMonitor_fn != nullptr) {
        // We're on Windows 8.1, we have per-system DPI
        // Note: MonitorFromWindow() is available on all Windows.

        const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        UINT dpiX;
        UINT dpiY;
        return GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI_, &dpiX, &dpiY) == S_OK ? dpiX : DPI_DEFAULT;
    } else {
        // We're on Windows earlier than 8.1, use DC

        const HDC hdc = GetDC(hwnd);
        if (hdc == NULL) { return DPI_DEFAULT; }
        return GetDeviceCaps(hdc, LOGPIXELSX);
    }
#elif defined __linux__
    // TODO
    return DPI_DEFAULT;
#elif defined __APPLE__
    // TODO
    return DPI_DEFAULT;
#endif
}

wxFont get_default_font_for_dpi(int dpi)
{
#ifdef _WIN32
    // First try to load the font with the Windows 10 specific way.
    struct SystemParametersInfoForDpi_t { typedef BOOL (WINAPI *FN)(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi); };
    static auto SystemParametersInfoForDpi_fn = winapi_get_function<SystemParametersInfoForDpi_t>(L"User32.dll", "SystemParametersInfoForDpi");
    if (SystemParametersInfoForDpi_fn != nullptr) {
        NONCLIENTMETRICS nm;
        memset(&nm, 0, sizeof(NONCLIENTMETRICS));
        nm.cbSize = sizeof(NONCLIENTMETRICS);
		if (SystemParametersInfoForDpi_fn(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nm, 0, dpi)) {
            wxNativeFontInfo info;
            info.lf = nm.lfMessageFont;
            return wxFont(info);
        }
    }
    // Then try to guesstimate the font DPI scaling on Windows 8.
    // Let's hope that the font returned by the SystemParametersInfo(), which is used by wxWidgets internally, makes sense.
    int dpi_primary = get_dpi_for_window(nullptr);
    if (dpi_primary != dpi) {
        // Rescale the font.
        return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scaled(float(dpi) / float(dpi_primary));
    }
#endif
    return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
}

CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent)
    : wxPanel(parent, wxID_ANY)
{
    // WARN: wxMSW does some extra shenanigans to calc the extra control size.
    // It first calls the create function with a dummy empty wxDialog parent and saves its size.
    // Afterwards, the create function is called again with the real parent.
    // Additionally there's no way to pass any extra data to the create function (no closure),
    // which is why we have to this stuff here. Grrr!
    auto *dlg = dynamic_cast<CheckboxFileDialog*>(parent);
    const wxString checkbox_label(dlg != nullptr ? dlg->checkbox_label : wxString("String long enough to contain dlg->checkbox_label"));

    auto* sizer = new wxBoxSizer(wxHORIZONTAL);
    cbox = new wxCheckBox(this, wxID_ANY, checkbox_label);
    cbox->SetValue(true);
    sizer->AddSpacer(5);
    sizer->Add(this->cbox, 0, wxEXPAND | wxALL, 5);
    SetSizer(sizer);
    sizer->SetSizeHints(this);
}

wxWindow* CheckboxFileDialog::ExtraPanel::ctor(wxWindow *parent) {
    return new ExtraPanel(parent);
}

CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent,
    const wxString &checkbox_label,
    bool checkbox_value,
    const wxString &message,
    const wxString &default_dir,
    const wxString &default_file,
    const wxString &wildcard,
    long style,
    const wxPoint &pos,
    const wxSize &size,
    const wxString &name
)
    : wxFileDialog(parent, message, default_dir, default_file, wildcard, style, pos, size, name)
    , checkbox_label(checkbox_label)
{
    if (checkbox_label.IsEmpty()) {
        return;
    }

    SetExtraControlCreator(ExtraPanel::ctor);
}

bool CheckboxFileDialog::get_checkbox_value() const
{
    auto *extra_panel = dynamic_cast<ExtraPanel*>(GetExtraControl());
    return extra_panel != nullptr ? extra_panel->cbox->GetValue() : false;
}

WindowMetrics WindowMetrics::from_window(wxTopLevelWindow *window)
{
    WindowMetrics res;
    res.rect = window->GetScreenRect();
    res.maximized = window->IsMaximized();
    return res;
}

boost::optional<WindowMetrics> WindowMetrics::deserialize(const std::string &str)
{
    std::vector<std::string> metrics_str;
    metrics_str.reserve(5);

    if (!unescape_strings_cstyle(str, metrics_str) || metrics_str.size() != 5) {
        return boost::none;
    }

    int metrics[5];
    try {
        for (size_t i = 0; i < 5; i++) {
            metrics[i] = boost::lexical_cast<int>(metrics_str[i]);
        }
    } catch(const boost::bad_lexical_cast &) {
        return boost::none;
    }

    if ((metrics[4] & ~1) != 0) {    // Checks if the maximized flag is 1 or 0
        metrics[4] = 0;
    }

    WindowMetrics res;
    res.rect = wxRect(metrics[0], metrics[1], metrics[2], metrics[3]);
    res.maximized = metrics[4] != 0;

    return res;
}

void WindowMetrics::sanitize_for_display(const wxRect &screen_rect)
{
    rect = rect.Intersect(screen_rect);

    // Prevent the window from going too far towards the right and/or bottom edge
    // It's hardcoded here that the threshold is 80% of the screen size
    rect.x = std::min(rect.x, screen_rect.x + 4*screen_rect.width/5);
    rect.y = std::min(rect.y, screen_rect.y + 4*screen_rect.height/5);
}

std::string WindowMetrics::serialize() const
{
    return (boost::format("%1%; %2%; %3%; %4%; %5%")
        % rect.x
        % rect.y
        % rect.width
        % rect.height
        % static_cast<int>(maximized)
    ).str();
}

std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics)
{
    return os << '(' << metrics.serialize() << ')';
}

}
}
<commit_msg>One more fix for Make compile and works for FreeBSD (#3556)<commit_after>#include "GUI_Utils.hpp"

#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

#ifdef _WIN32
#include <Windows.h>
#endif

#include <wx/toplevel.h>
#include <wx/sizer.h>
#include <wx/checkbox.h>
#include <wx/dcclient.h>
#include <wx/font.h>
#include <wx/fontutil.h>

#include "libslic3r/Config.hpp"

namespace Slic3r {
namespace GUI {

wxTopLevelWindow* find_toplevel_parent(wxWindow *window)
{
    for (; window != nullptr; window = window->GetParent()) {
        if (window->IsTopLevel()) {
            return dynamic_cast<wxTopLevelWindow*>(window);
        }
    }

    return nullptr;
}

void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback)
{
#ifdef _WIN32
    // On windows, the wxEVT_SHOW is not received if the window is created maximized
    // cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI
    // OTOH the geometry is available very soon, so we can call the callback right away
    callback();
#elif defined __linux__
    tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) {
        // On Linux, the geometry is only available after wxEVT_SHOW + CallAfter
        // cf. https://groups.google.com/forum/?pli=1#!topic/wx-users/fERSXdpVwAI
        tlw->CallAfter([=]() { callback(); });
        evt.Skip();
    });
#elif defined __APPLE__
    tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) {
        callback();
        evt.Skip();
    });
#endif
}

wxDEFINE_EVENT(EVT_DPI_CHANGED_SLICER, DpiChangedEvent);

#ifdef _WIN32
template<class F> typename F::FN winapi_get_function(const wchar_t *dll, const char *fn_name) {
    static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0);

    if (dll_handle == nullptr) { return nullptr; }
    return (typename F::FN)GetProcAddress(dll_handle, fn_name);
}
#endif

// If called with nullptr, a DPI for the primary monitor is returned.
int get_dpi_for_window(wxWindow *window)
{
#ifdef _WIN32
    enum MONITOR_DPI_TYPE_ {
        // This enum is inlined here to avoid build-time dependency
        MDT_EFFECTIVE_DPI_ = 0,
        MDT_ANGULAR_DPI_ = 1,
        MDT_RAW_DPI_ = 2,
        MDT_DEFAULT_ = MDT_EFFECTIVE_DPI_,
    };

    // Need strong types for winapi_get_function() to work
    struct GetDpiForWindow_t { typedef HRESULT (WINAPI *FN)(HWND hwnd); };
    struct GetDpiForMonitor_t { typedef HRESULT (WINAPI *FN)(HMONITOR hmonitor, MONITOR_DPI_TYPE_ dpiType, UINT *dpiX, UINT *dpiY); };

    static auto GetDpiForWindow_fn = winapi_get_function<GetDpiForWindow_t>(L"User32.dll", "GetDpiForWindow");
    static auto GetDpiForMonitor_fn = winapi_get_function<GetDpiForMonitor_t>(L"Shcore.dll", "GetDpiForMonitor");

	// Desktop Window is the window of the primary monitor.
	const HWND hwnd = (window == nullptr) ? ::GetDesktopWindow() : window->GetHandle();

    if (GetDpiForWindow_fn != nullptr) {
        // We're on Windows 10, we have per-screen DPI settings
        return GetDpiForWindow_fn(hwnd);
    } else if (GetDpiForMonitor_fn != nullptr) {
        // We're on Windows 8.1, we have per-system DPI
        // Note: MonitorFromWindow() is available on all Windows.

        const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        UINT dpiX;
        UINT dpiY;
        return GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI_, &dpiX, &dpiY) == S_OK ? dpiX : DPI_DEFAULT;
    } else {
        // We're on Windows earlier than 8.1, use DC

        const HDC hdc = GetDC(hwnd);
        if (hdc == NULL) { return DPI_DEFAULT; }
        return GetDeviceCaps(hdc, LOGPIXELSX);
    }
#elif defined __linux__
    // TODO
    return DPI_DEFAULT;
#elif defined __APPLE__
    // TODO
    return DPI_DEFAULT;
#else // freebsd and others
    // TODO
    return DPI_DEFAULT;
#endif
}

wxFont get_default_font_for_dpi(int dpi)
{
#ifdef _WIN32
    // First try to load the font with the Windows 10 specific way.
    struct SystemParametersInfoForDpi_t { typedef BOOL (WINAPI *FN)(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi); };
    static auto SystemParametersInfoForDpi_fn = winapi_get_function<SystemParametersInfoForDpi_t>(L"User32.dll", "SystemParametersInfoForDpi");
    if (SystemParametersInfoForDpi_fn != nullptr) {
        NONCLIENTMETRICS nm;
        memset(&nm, 0, sizeof(NONCLIENTMETRICS));
        nm.cbSize = sizeof(NONCLIENTMETRICS);
		if (SystemParametersInfoForDpi_fn(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nm, 0, dpi)) {
            wxNativeFontInfo info;
            info.lf = nm.lfMessageFont;
            return wxFont(info);
        }
    }
    // Then try to guesstimate the font DPI scaling on Windows 8.
    // Let's hope that the font returned by the SystemParametersInfo(), which is used by wxWidgets internally, makes sense.
    int dpi_primary = get_dpi_for_window(nullptr);
    if (dpi_primary != dpi) {
        // Rescale the font.
        return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scaled(float(dpi) / float(dpi_primary));
    }
#endif
    return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
}

CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent)
    : wxPanel(parent, wxID_ANY)
{
    // WARN: wxMSW does some extra shenanigans to calc the extra control size.
    // It first calls the create function with a dummy empty wxDialog parent and saves its size.
    // Afterwards, the create function is called again with the real parent.
    // Additionally there's no way to pass any extra data to the create function (no closure),
    // which is why we have to this stuff here. Grrr!
    auto *dlg = dynamic_cast<CheckboxFileDialog*>(parent);
    const wxString checkbox_label(dlg != nullptr ? dlg->checkbox_label : wxString("String long enough to contain dlg->checkbox_label"));

    auto* sizer = new wxBoxSizer(wxHORIZONTAL);
    cbox = new wxCheckBox(this, wxID_ANY, checkbox_label);
    cbox->SetValue(true);
    sizer->AddSpacer(5);
    sizer->Add(this->cbox, 0, wxEXPAND | wxALL, 5);
    SetSizer(sizer);
    sizer->SetSizeHints(this);
}

wxWindow* CheckboxFileDialog::ExtraPanel::ctor(wxWindow *parent) {
    return new ExtraPanel(parent);
}

CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent,
    const wxString &checkbox_label,
    bool checkbox_value,
    const wxString &message,
    const wxString &default_dir,
    const wxString &default_file,
    const wxString &wildcard,
    long style,
    const wxPoint &pos,
    const wxSize &size,
    const wxString &name
)
    : wxFileDialog(parent, message, default_dir, default_file, wildcard, style, pos, size, name)
    , checkbox_label(checkbox_label)
{
    if (checkbox_label.IsEmpty()) {
        return;
    }

    SetExtraControlCreator(ExtraPanel::ctor);
}

bool CheckboxFileDialog::get_checkbox_value() const
{
    auto *extra_panel = dynamic_cast<ExtraPanel*>(GetExtraControl());
    return extra_panel != nullptr ? extra_panel->cbox->GetValue() : false;
}

WindowMetrics WindowMetrics::from_window(wxTopLevelWindow *window)
{
    WindowMetrics res;
    res.rect = window->GetScreenRect();
    res.maximized = window->IsMaximized();
    return res;
}

boost::optional<WindowMetrics> WindowMetrics::deserialize(const std::string &str)
{
    std::vector<std::string> metrics_str;
    metrics_str.reserve(5);

    if (!unescape_strings_cstyle(str, metrics_str) || metrics_str.size() != 5) {
        return boost::none;
    }

    int metrics[5];
    try {
        for (size_t i = 0; i < 5; i++) {
            metrics[i] = boost::lexical_cast<int>(metrics_str[i]);
        }
    } catch(const boost::bad_lexical_cast &) {
        return boost::none;
    }

    if ((metrics[4] & ~1) != 0) {    // Checks if the maximized flag is 1 or 0
        metrics[4] = 0;
    }

    WindowMetrics res;
    res.rect = wxRect(metrics[0], metrics[1], metrics[2], metrics[3]);
    res.maximized = metrics[4] != 0;

    return res;
}

void WindowMetrics::sanitize_for_display(const wxRect &screen_rect)
{
    rect = rect.Intersect(screen_rect);

    // Prevent the window from going too far towards the right and/or bottom edge
    // It's hardcoded here that the threshold is 80% of the screen size
    rect.x = std::min(rect.x, screen_rect.x + 4*screen_rect.width/5);
    rect.y = std::min(rect.y, screen_rect.y + 4*screen_rect.height/5);
}

std::string WindowMetrics::serialize() const
{
    return (boost::format("%1%; %2%; %3%; %4%; %5%")
        % rect.x
        % rect.y
        % rect.width
        % rect.height
        % static_cast<int>(maximized)
    ).str();
}

std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics)
{
    return os << '(' << metrics.serialize() << ')';
}

}
}
<|endoftext|>


<commit_before>#include "TextInputWidget.hpp"
#include <iostream>

gsf::TextInputWidget::TextInputWidget(float width, float height, sf::Font &font)
: ChildWidget{ width, height }
//, m_text{ "", font, 12, sf::Color::Black }
, m_text{ nullptr }
, m_font{ font }
, m_charSize{ 12 }
, m_isEditable{ true }
, m_cursor{ "|", font, m_charSize }
, m_scrollable{ nullptr }
, m_acceptNewLines{ true }
, m_isFocused{ false }
, m_cursorPos{ 0 }
, m_lBreaksBefCur{ 0 }
, m_isCursorShown{ true }
, m_blinkFreq{ 0.8f }
, m_lastBlinkTime{ 0.f }
, m_minBreakCharCnt{ 0 }
{
    std::unique_ptr<TextWidget> text{
        std::make_unique<TextWidget>("", font, m_charSize, sf::Color::Black) };
    std::unique_ptr<ScrollableWidget> scrollabe{
        std::make_unique<ScrollableWidget>(width, height) };
    m_scrollable = scrollabe.get();
    m_text = text.get();
    scrollabe->setBackgroundColor(sf::Color::Transparent);
    scrollabe->attachChild(std::move(text));
    //attachChild(std::move(text));
    attachChild(std::move(scrollabe));
    m_cursor.setFillColor(sf::Color::Black);
}

void gsf::TextInputWidget::setIsEditable(bool isEditable)
{
    m_isEditable = isEditable;
}

bool gsf::TextInputWidget::isEditable() const
{
    return m_isEditable;
}

void gsf::TextInputWidget::setText(const std::wstring &text)
{
    m_currentText = text;
    m_text->setText(m_currentText);
    // Move cursor to end of text
    m_cursorPos = m_currentText.size();
    // Adjust text so that it fits the scrollbar when horizontal scrolling is disabled
    adjustShownText();
    m_scrollable->recalculateScroll();
    m_scrollable->scrollToBottom();
}

std::wstring gsf::TextInputWidget::getText() const
{
    //return m_text->getText().toWideString();
    return m_currentText;
}

void gsf::TextInputWidget::setCharacterSize(const unsigned int size)
{
    m_text->setCharacterSize(size);
    m_charSize = size;
    m_cursor.setCharacterSize(size);
}

unsigned int gsf::TextInputWidget::getCharacterSize() const
{
    return m_charSize;
}

void gsf::TextInputWidget::setTextColor(const sf::Color color)
{
    m_text->setTextColor(color);
}

sf::Color gsf::TextInputWidget::getTextColor() const
{
    return m_text->getTextColor();
}

void gsf::TextInputWidget::setIsNewLineAccepted(bool isAccepted)
{
    m_acceptNewLines = isAccepted;
}

bool gsf::TextInputWidget::getIsNewLineAccepted() const
{
    return m_acceptNewLines;
}

bool gsf::TextInputWidget::isFocused() const
{
    return m_isFocused;
}

void gsf::TextInputWidget::setIsVerticalScrollEnabled(bool isEnabled)
{
    m_scrollable->setIsVerticalScrollEnabled(isEnabled);
}

bool gsf::TextInputWidget::isVerticalScrollEnabled() const
{
    return m_scrollable->isVerticalScrollEnabled();
}

void gsf::TextInputWidget::setIsHorizontalScrollEnabled(bool isEnabled)
{
    m_scrollable->setIsHorizontalScrollEnabled(isEnabled);
}

bool gsf::TextInputWidget::isHorizontalScrollEnabled() const
{
    return m_scrollable->isHorizontalScrollEnabled();
}

void gsf::TextInputWidget::setIsVerticalScrollbarDrawn(bool isDrawn)
{
    m_scrollable->setIsVerticalScrollbarDrawn(isDrawn);
}

void gsf::TextInputWidget::setIsHorizontalScrollbarDrawn(bool isDrawn)
{
    m_scrollable->setIsHorizontalScrollbarDrawn(isDrawn);
}
void gsf::TextInputWidget::drawCurrent(sf::RenderTarget &target,
        sf::RenderStates states) const
{

}

void gsf::TextInputWidget::drawCurrentAfterChildren(sf::RenderTarget &target,
                    sf::RenderStates states) const
{
    // Draw cursor after children, so that children are not drawn over cursor
    if (m_isCursorShown && m_isEditable)
    {
        target.draw(m_cursor, states);
    }
}

void gsf::TextInputWidget::updateCurrent(float dt)
{
    if (!m_isEditable)
    {
        // Nothing to do
        return;
    }

    // Update cursor stuff
    m_lastBlinkTime += dt;
    if (m_lastBlinkTime >= m_blinkFreq)
    {
        m_isCursorShown = !m_isCursorShown;
        m_lastBlinkTime = 0.f;
    }

    m_cursor.setPosition(m_text->findGlobalCharacterPos(m_cursorPos + m_lBreaksBefCur));
    //std::wstring text{ m_currentText };
    //std::wstring text{ m_shownText };
    //m_text->setText(text);
}

bool gsf::TextInputWidget::handleEventCurrent(sf::Event &event)
{
    if (!m_isEditable)
    {
        // Nothing to do
        return false;
    }
    //bool handled{ ChildWidget::handleEvent(event) };/*||
      //  m_scrollable->handleEventWidget(event) };*/
    // Check if actual Widget is focused
    if (event.type == sf::Event::MouseButtonPressed)
    {
        sf::Vector2f mousePos{ (float) event.mouseButton.x,
        (float) event.mouseButton.y };

        //sf::Vector2f localPos{ mousePos.x - getWorldPosition().x,
        //    mousePos.y - getWorldPosition().y };
        //std::cout << "pressed on: " << findIndexOfCharOnPos(localPos);

        bool isMouseInShownArea{ getShownArea().contains(mousePos) };
        bool intersecting{ isIntersecting(mousePos) };
        if (isMouseInShownArea && intersecting)
        {
            m_isFocused = true;
        }
        else
        {
            m_isFocused = false;
        }
    }
    if (event.type == sf::Event::KeyPressed && m_isFocused)
    {
        switch (event.key.code)
        {
        case sf::Keyboard::Left:
            if (m_cursorPos > 0)
            {
                m_cursorPos--;
            }
            // when cursor is moved it should be drawn so we reset its status
            resetCursorStatus();
            adjustShownText();
            //m_cursor.setPosition(
            //    m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
            return true;
        case sf::Keyboard::Right:
            if (m_cursorPos < m_currentText.length())
            {
                m_cursorPos++;
            }
            resetCursorStatus();
            adjustShownText();
            //m_cursor.setPosition
            //    (m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
            return true;
        default: break;
        }
    }
    // If Widget is focused and Text entered, handle entered text
    if (m_isFocused && event.type == sf::Event::TextEntered)
    {
        // To handle umlauts and other 'exotic' chars we use widestring
        // and wide char
        //std::wstring actualTxt{ m_text.getString().toWideString() };
        wchar_t c{ static_cast<wchar_t>(event.text.unicode) };
        std::cout << "Entered: " << c << std::endl;
        switch (c)
        {
        // Backspace
        case 8:
            if (m_currentText.length() > 0)
            {
                // Remove chars right of cursor when there are chars
                if (m_cursorPos > 0 && m_cursorPos < m_currentText.length())
                {
                    m_currentText.erase(m_cursorPos - 1, 1);
                    m_cursorPos--;
                }
                // When cursos is at the end of the text, p
                // place cursor behind char which we want to delete,
                else if (m_cursorPos == m_currentText.length())
                {
                    // Delete last char
                    m_currentText.pop_back();
                    m_cursorPos--;
                }
            }
            break;
        // Delete Pressed
        case 127:
            if (m_currentText.length() > 0 &&
                    m_cursorPos < m_currentText.length())
            {
                m_currentText.erase(m_cursorPos, 1);
            }
            break;
        // Enter key
        case 13:
            // Dont add new line, when new lines are not accepted
            if (!m_acceptNewLines)
            {
                return false;
            }
            m_currentText.insert(m_cursorPos, L"\n"); m_cursorPos++;
            break;
        // Add char to text
        default: m_currentText.insert(m_cursorPos, std::wstring() + c); m_cursorPos++;
        }
        resetCursorStatus();
        m_shownText = m_currentText;
        m_text->setText(m_shownText);
        adjustShownText();
        //m_cursor.setPosition
            //(m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
        m_scrollable->recalculateScroll();
        m_scrollable->scrollToRight();
        m_scrollable->scrollToBottom();
        return true;
    }
    return false;
    //return handled;
}

void gsf::TextInputWidget::adjustShownText()
{
    if (!m_scrollable->isHorizontalScrollEnabled() && m_currentText.size() > 0)
    {
        m_lBreaksBefCur = 0;
        std::wstring shownString{ L"" };
        // The chars which are in the actual line
        unsigned int charCntLine{ 0 };
        // The total width of all chars in the current line
        float lineWidth{ 0.f };
        for (unsigned int i{ 0 }; i < m_currentText.size(); i++)
        {
            wchar_t c{ m_currentText[i] };
            // Width of the current char
            float cWidth{ m_text->getWidthAndHeightOfChar(c).x };
            lineWidth += cWidth;
            // When Text is out of scrollable widget, we have to add a new line
            if (lineWidth > m_scrollable->getWidth())
            {
                if (i < m_cursorPos)
                {
                    // We have to increase the "line breaks befor cursor" counter
                    // so we add the cursor later on the right position
                    m_lBreaksBefCur++;
                }
                //shownString += m_currentText.substr(i - charCntLine, charCntLine);
                // Add new line
                shownString += L"\n";
                // add the char with which the line was to wide in the new line
                shownString += c;
                // We have added the char c in the new line,
                // so we have now 1 char in the current line
                charCntLine = 1;
                lineWidth = cWidth;
            }
            else
            {
                charCntLine++;
                shownString += c;
            }
        }
        m_shownText = shownString;
        m_text->setText(m_shownText);
    }
}

// Use binary search to get the right position
int gsf::TextInputWidget::findIndexOfCharOnPos(sf::Vector2f localPos) const
{
    return findCharOnPosBinary(localPos, 0, m_text->getWideText().size() - 1);
}

int gsf::TextInputWidget::findCharOnPosBinary(sf::Vector2f localPos, std::size_t l,
    std::size_t r) const
{
    // Nothing found
    if (r <= l)
    {
        return -1;
    }
    // Get center as index
    //std::size_t i{ static_cast<std::size_t>( (r - l) / 2 )};
    int i = (r - l) / 2;
    std::cout << "Index: " << i << std::endl;
    sf::FloatRect cRect{ m_text->getLocalBoundsOfChar(i) };

    //    ++++++++
    //    ++++c---
    //    --------
    //
    //    c : index of i
    //    + : left of i
    //    - : right of i

    // Found char (case c)
    if (cRect.contains(localPos))
    {
        return i;
    }
    // Left of i (case +)
    if ( (localPos.x < cRect.left && localPos.y <= cRect.top + cRect.height) ||
            (localPos.x > cRect.left && localPos.y < cRect.top) )
    {
        return findCharOnPosBinary(localPos, l, i - 1);
    }
    // Right of i (case -)
    else
    {
        return findCharOnPosBinary(localPos, i + 1, r);
    }
}

void gsf::TextInputWidget::resetCursorStatus()
{
    m_lastBlinkTime = 0.f;
    m_isCursorShown = true;
}
<commit_msg>Better adjusting of the text in TextInputWidget<commit_after>#include "TextInputWidget.hpp"
#include <iostream>

gsf::TextInputWidget::TextInputWidget(float width, float height, sf::Font &font)
: ChildWidget{ width, height }
//, m_text{ "", font, 12, sf::Color::Black }
, m_text{ nullptr }
, m_font{ font }
, m_charSize{ 12 }
, m_isEditable{ true }
, m_cursor{ "|", font, m_charSize }
, m_scrollable{ nullptr }
, m_acceptNewLines{ true }
, m_isFocused{ false }
, m_cursorPos{ 0 }
, m_lBreaksBefCur{ 0 }
, m_isCursorShown{ true }
, m_blinkFreq{ 0.8f }
, m_lastBlinkTime{ 0.f }
, m_minBreakCharCnt{ 0 }
{
    std::unique_ptr<TextWidget> text{
        std::make_unique<TextWidget>("", font, m_charSize, sf::Color::Black) };
    std::unique_ptr<ScrollableWidget> scrollabe{
        std::make_unique<ScrollableWidget>(width, height) };
    m_scrollable = scrollabe.get();
    m_text = text.get();
    scrollabe->setBackgroundColor(sf::Color::Transparent);
    scrollabe->attachChild(std::move(text));
    //attachChild(std::move(text));
    attachChild(std::move(scrollabe));
    m_cursor.setFillColor(sf::Color::Black);
}

void gsf::TextInputWidget::setIsEditable(bool isEditable)
{
    m_isEditable = isEditable;
}

bool gsf::TextInputWidget::isEditable() const
{
    return m_isEditable;
}

void gsf::TextInputWidget::setText(const std::wstring &text)
{
    m_currentText = text;
    m_text->setText(m_currentText);
    // Move cursor to end of text
    m_cursorPos = m_currentText.size();
    // Adjust text so that it fits the scrollbar when horizontal scrolling is disabled
    adjustShownText();
    m_scrollable->recalculateScroll();
    m_scrollable->scrollToBottom();
}

std::wstring gsf::TextInputWidget::getText() const
{
    //return m_text->getText().toWideString();
    return m_currentText;
}

void gsf::TextInputWidget::setCharacterSize(const unsigned int size)
{
    m_text->setCharacterSize(size);
    m_charSize = size;
    m_cursor.setCharacterSize(size);
}

unsigned int gsf::TextInputWidget::getCharacterSize() const
{
    return m_charSize;
}

void gsf::TextInputWidget::setTextColor(const sf::Color color)
{
    m_text->setTextColor(color);
}

sf::Color gsf::TextInputWidget::getTextColor() const
{
    return m_text->getTextColor();
}

void gsf::TextInputWidget::setIsNewLineAccepted(bool isAccepted)
{
    m_acceptNewLines = isAccepted;
}

bool gsf::TextInputWidget::getIsNewLineAccepted() const
{
    return m_acceptNewLines;
}

bool gsf::TextInputWidget::isFocused() const
{
    return m_isFocused;
}

void gsf::TextInputWidget::setIsVerticalScrollEnabled(bool isEnabled)
{
    m_scrollable->setIsVerticalScrollEnabled(isEnabled);
}

bool gsf::TextInputWidget::isVerticalScrollEnabled() const
{
    return m_scrollable->isVerticalScrollEnabled();
}

void gsf::TextInputWidget::setIsHorizontalScrollEnabled(bool isEnabled)
{
    m_scrollable->setIsHorizontalScrollEnabled(isEnabled);
}

bool gsf::TextInputWidget::isHorizontalScrollEnabled() const
{
    return m_scrollable->isHorizontalScrollEnabled();
}

void gsf::TextInputWidget::setIsVerticalScrollbarDrawn(bool isDrawn)
{
    m_scrollable->setIsVerticalScrollbarDrawn(isDrawn);
}

void gsf::TextInputWidget::setIsHorizontalScrollbarDrawn(bool isDrawn)
{
    m_scrollable->setIsHorizontalScrollbarDrawn(isDrawn);
}
void gsf::TextInputWidget::drawCurrent(sf::RenderTarget &target,
        sf::RenderStates states) const
{

}

void gsf::TextInputWidget::drawCurrentAfterChildren(sf::RenderTarget &target,
                    sf::RenderStates states) const
{
    // Draw cursor after children, so that children are not drawn over cursor
    if (m_isCursorShown && m_isEditable)
    {
        target.draw(m_cursor, states);
    }
}

void gsf::TextInputWidget::updateCurrent(float dt)
{
    if (!m_isEditable)
    {
        // Nothing to do
        return;
    }

    // Update cursor stuff
    m_lastBlinkTime += dt;
    if (m_lastBlinkTime >= m_blinkFreq)
    {
        m_isCursorShown = !m_isCursorShown;
        m_lastBlinkTime = 0.f;
    }

    m_cursor.setPosition(m_text->findGlobalCharacterPos(m_cursorPos + m_lBreaksBefCur));
    //std::wstring text{ m_currentText };
    //std::wstring text{ m_shownText };
    //m_text->setText(text);
}

bool gsf::TextInputWidget::handleEventCurrent(sf::Event &event)
{
    if (!m_isEditable)
    {
        // Nothing to do
        return false;
    }
    //bool handled{ ChildWidget::handleEvent(event) };/*||
      //  m_scrollable->handleEventWidget(event) };*/
    // Check if actual Widget is focused
    if (event.type == sf::Event::MouseButtonPressed)
    {
        sf::Vector2f mousePos{ (float) event.mouseButton.x,
        (float) event.mouseButton.y };

        //sf::Vector2f localPos{ mousePos.x - getWorldPosition().x,
        //    mousePos.y - getWorldPosition().y };
        //std::cout << "pressed on: " << findIndexOfCharOnPos(localPos);

        bool isMouseInShownArea{ getShownArea().contains(mousePos) };
        bool intersecting{ isIntersecting(mousePos) };
        if (isMouseInShownArea && intersecting)
        {
            m_isFocused = true;
        }
        else
        {
            m_isFocused = false;
        }
    }
    if (event.type == sf::Event::KeyPressed && m_isFocused)
    {
        switch (event.key.code)
        {
        case sf::Keyboard::Left:
            if (m_cursorPos > 0)
            {
                m_cursorPos--;
            }
            // when cursor is moved it should be drawn so we reset its status
            resetCursorStatus();
            adjustShownText();
            //m_cursor.setPosition(
            //    m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
            return true;
        case sf::Keyboard::Right:
            if (m_cursorPos < m_currentText.length())
            {
                m_cursorPos++;
            }
            resetCursorStatus();
            adjustShownText();
            //m_cursor.setPosition
            //    (m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
            return true;
        default: break;
        }
    }
    // If Widget is focused and Text entered, handle entered text
    if (m_isFocused && event.type == sf::Event::TextEntered)
    {
        // To handle umlauts and other 'exotic' chars we use widestring
        // and wide char
        //std::wstring actualTxt{ m_text.getString().toWideString() };
        wchar_t c{ static_cast<wchar_t>(event.text.unicode) };
        std::cout << "Entered: " << c << std::endl;
        switch (c)
        {
        // Backspace
        case 8:
            if (m_currentText.length() > 0)
            {
                // Remove chars right of cursor when there are chars
                if (m_cursorPos > 0 && m_cursorPos < m_currentText.length())
                {
                    m_currentText.erase(m_cursorPos - 1, 1);
                    m_cursorPos--;
                }
                // When cursos is at the end of the text, p
                // place cursor behind char which we want to delete,
                else if (m_cursorPos == m_currentText.length())
                {
                    // Delete last char
                    m_currentText.pop_back();
                    m_cursorPos--;
                }
            }
            break;
        // Delete Pressed
        case 127:
            if (m_currentText.length() > 0 &&
                    m_cursorPos < m_currentText.length())
            {
                m_currentText.erase(m_cursorPos, 1);
            }
            break;
        // Enter key
        case 13:
            // Dont add new line, when new lines are not accepted
            if (!m_acceptNewLines)
            {
                return false;
            }
            m_currentText.insert(m_cursorPos, L"\n"); m_cursorPos++;
            break;
        // Add char to text
        default: m_currentText.insert(m_cursorPos, std::wstring() + c); m_cursorPos++;
        }
        resetCursorStatus();
        m_shownText = m_currentText;
        m_text->setText(m_shownText);
        adjustShownText();
        //m_cursor.setPosition
            //(m_text->findCharacterPos(m_cursorPos + m_lBreaksBefCur));
        m_scrollable->recalculateScroll();
        m_scrollable->scrollToRight();
        m_scrollable->scrollToBottom();
        return true;
    }
    return false;
    //return handled;
}

void gsf::TextInputWidget::adjustShownText()
{
    if (!m_scrollable->isHorizontalScrollEnabled() && m_currentText.size() > 0)
    {
        m_lBreaksBefCur = 0;
        std::wstring shownString{ L"" };
        // The chars which are in the actual line
        unsigned int charCntLine{ 0 };
        // The total width of all chars in the current line
        float lineWidth{ 0.f };
        for (unsigned int i{ 0 }; i < m_currentText.size(); i++)
        {
            wchar_t c{ m_currentText[i] };
            // If we have a new line as char we can set the lineWidth and charCntLine
            // to 0 because there is no need to handle the chars in this line
            // (It is already handled by user width the new line char)
            if (c == '\n')
            {
                lineWidth = 0.f;
                charCntLine = 0;
                shownString += c;
                continue;
            }
            // Width of the current char
            float cWidth{ m_text->getWidthAndHeightOfChar(c).x };
            lineWidth += cWidth;
            // When Text is out of scrollable widget, we have to add a new line
            if (lineWidth > m_scrollable->getWidth())
            {
                if (i < m_cursorPos)
                {
                    // We have to increase the "line breaks befor cursor" counter
                    // so we add the cursor later on the right position
                    m_lBreaksBefCur++;
                }
                //shownString += m_currentText.substr(i - charCntLine, charCntLine);
                // Add new line
                shownString += L"\n";
                // add the char with which the line was to wide in the new line
                shownString += c;
                // We have added the char c in the new line,
                // so we have now 1 char in the current line
                charCntLine = 1;
                lineWidth = cWidth;
            }
            else
            {
                charCntLine++;
                shownString += c;
            }
        }
        m_shownText = shownString;
        m_text->setText(m_shownText);
    }
}

// Use binary search to get the right position
int gsf::TextInputWidget::findIndexOfCharOnPos(sf::Vector2f localPos) const
{
    return findCharOnPosBinary(localPos, 0, m_text->getWideText().size() - 1);
}

int gsf::TextInputWidget::findCharOnPosBinary(sf::Vector2f localPos, std::size_t l,
    std::size_t r) const
{
    // Nothing found
    if (r <= l)
    {
        return -1;
    }
    // Get center as index
    //std::size_t i{ static_cast<std::size_t>( (r - l) / 2 )};
    int i = (r - l) / 2;
    std::cout << "Index: " << i << std::endl;
    sf::FloatRect cRect{ m_text->getLocalBoundsOfChar(i) };

    //    ++++++++
    //    ++++c---
    //    --------
    //
    //    c : index of i
    //    + : left of i
    //    - : right of i

    // Found char (case c)
    if (cRect.contains(localPos))
    {
        return i;
    }
    // Left of i (case +)
    if ( (localPos.x < cRect.left && localPos.y <= cRect.top + cRect.height) ||
            (localPos.x > cRect.left && localPos.y < cRect.top) )
    {
        return findCharOnPosBinary(localPos, l, i - 1);
    }
    // Right of i (case -)
    else
    {
        return findCharOnPosBinary(localPos, i + 1, r);
    }
}

void gsf::TextInputWidget::resetCursorStatus()
{
    m_lastBlinkTime = 0.f;
    m_isCursorShown = true;
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include <string>

#include <SurgSim/Physics/FixedRepresentation.h>
using SurgSim::Physics::Representation;
using SurgSim::Physics::FixedRepresentation;

#include <SurgSim/Math/Vector.h>
#include <SurgSim/Math/Quaternion.h>
#include <SurgSim/Math/RigidTransform.h>
using SurgSim::Math::Vector3d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;

class FixedRepresentationTest : public ::testing::Test
{
public:
	void SetUp()
	{
		Quaterniond q;
		Vector3d t;

		q.coeffs().setRandom();
		q.normalize();
		t.setRandom();
		m_initialTransformation = SurgSim::Math::makeRigidTransform(q, t);

		do
		{
			q.coeffs().setRandom();
			q.normalize();
			t.setRandom();
			m_currentTransformation = SurgSim::Math::makeRigidTransform(q, t);
		} while (m_initialTransformation.isApprox(m_currentTransformation));

		m_identityTransformation.setIdentity();
	}

	void TearDown()
	{
	}

	// Fixed representation initialization pose
	RigidTransform3d m_initialTransformation;

	// Fixed representation current pose
	RigidTransform3d m_currentTransformation;

	// Identity pose (no translation/rotation)
	RigidTransform3d m_identityTransformation;
};

TEST_F(FixedRepresentationTest, ConstructorTest)
{
	ASSERT_NO_THROW( {FixedRepresentation fixedRepresentation("FixedRepresentation");});
}

TEST_F(FixedRepresentationTest, ResetStateTest)
{
	// Create the rigid body
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	fixedRepresentation->setIsActive(false);
	fixedRepresentation->setIsGravityEnabled(false);
	fixedRepresentation->setInitialPose(m_initialTransformation);
	// Initial = Current = Previous = Final = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getInitialPose().isApprox(m_initialTransformation));

	fixedRepresentation->setCurrentPose(m_currentTransformation);
	// setCurrent is supposed to backup current in previous and set current
	// Therefore it should not affect initial nor final
	// Initial = Final = Previous = m_initialTransformation
	// Current = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getFinalPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	fixedRepresentation->setCurrentPose(m_currentTransformation);
	// setCurrent is supposed to backup current in previous and set current
	// Therefore it should not affect initial nor final
	// Initial = Final = m_initialTransformation
	// Previous = Current = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_FALSE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_FALSE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getFinalPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	fixedRepresentation->afterUpdate(1.0);
	// afterUpdate simply backs up the current into the final
	// Initial = m_initialTransformation
	// Previous = Current = Final = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	std::shared_ptr<Representation> representation = fixedRepresentation;
	// reset the representation (NOT THE FIXED ACTOR, test polymorphism)
	representation->resetState();

	// isActive flag unchanged
	EXPECT_FALSE(fixedRepresentation->isActive());
	// isGravityEnable flag unchanged
	EXPECT_FALSE(fixedRepresentation->isGravityEnabled());
	// The current rigid state should be exactly the initial rigid state
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getInitialPose().isApprox(m_initialTransformation));
	// The previous rigid state should be exactly the initial rigid state
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(m_initialTransformation));
}

TEST_F(FixedRepresentationTest, SetGetAndDefaultValueTest)
{
	// Create the fixed representation
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	// Get/Set active flag [default = true]
	EXPECT_TRUE(fixedRepresentation->isActive());
	fixedRepresentation->setIsActive(false);
	ASSERT_FALSE(fixedRepresentation->isActive());
	fixedRepresentation->setIsActive(true);
	ASSERT_TRUE(fixedRepresentation->isActive());

	// Get numDof = 0
	ASSERT_EQ(0u, fixedRepresentation->getNumDof());

	// Set/Get isGravityEnabled [default = true]
	EXPECT_TRUE(fixedRepresentation->isGravityEnabled());
	fixedRepresentation->setIsGravityEnabled(false);
	ASSERT_FALSE(fixedRepresentation->isGravityEnabled());
	fixedRepresentation->setIsGravityEnabled(true);
	ASSERT_TRUE(fixedRepresentation->isGravityEnabled());

	// Set/Get current pose [default = no translation, no rotation]
	EXPECT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getFinalPose()));
	fixedRepresentation->setCurrentPose(m_currentTransformation);
	fixedRepresentation->afterUpdate(1.0); // afterUpdate backs up current into final
	ASSERT_TRUE(m_currentTransformation.isApprox(fixedRepresentation->getFinalPose()));
	fixedRepresentation->setCurrentPose(m_identityTransformation);
	fixedRepresentation->afterUpdate(1.0); // afterUpdate backs up current into final
	ASSERT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getFinalPose()));

	// Set/Get initial pose [default = no translation, no rotation]
	EXPECT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getInitialPose()));
	fixedRepresentation->setInitialPose(m_initialTransformation);
	ASSERT_TRUE(m_initialTransformation.isApprox(fixedRepresentation->getInitialPose()));
	fixedRepresentation->setInitialPose(m_identityTransformation);
	ASSERT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getInitialPose()));
}

TEST_F(FixedRepresentationTest, UpdateTest)
{
	// Create the fixed representation
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	double dt = 1.0;

	// Sets Initial state and reset all other state with initial state
	fixedRepresentation->setInitialPose(m_initialTransformation);
	// Backs up current state into previous state and set the current
	fixedRepresentation->setCurrentPose(m_currentTransformation);

	// Does not do anything
	fixedRepresentation->beforeUpdate(dt);
	// Does not do anything
	fixedRepresentation->update(dt);
	// Backs up current state into final state
	fixedRepresentation->afterUpdate(dt);

	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getPreviousPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
}
<commit_msg>One last ACTOR to REPRESENTATION rename.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <string>

#include <SurgSim/Physics/FixedRepresentation.h>
using SurgSim::Physics::Representation;
using SurgSim::Physics::FixedRepresentation;

#include <SurgSim/Math/Vector.h>
#include <SurgSim/Math/Quaternion.h>
#include <SurgSim/Math/RigidTransform.h>
using SurgSim::Math::Vector3d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;

class FixedRepresentationTest : public ::testing::Test
{
public:
	void SetUp()
	{
		Quaterniond q;
		Vector3d t;

		q.coeffs().setRandom();
		q.normalize();
		t.setRandom();
		m_initialTransformation = SurgSim::Math::makeRigidTransform(q, t);

		do
		{
			q.coeffs().setRandom();
			q.normalize();
			t.setRandom();
			m_currentTransformation = SurgSim::Math::makeRigidTransform(q, t);
		} while (m_initialTransformation.isApprox(m_currentTransformation));

		m_identityTransformation.setIdentity();
	}

	void TearDown()
	{
	}

	// Fixed representation initialization pose
	RigidTransform3d m_initialTransformation;

	// Fixed representation current pose
	RigidTransform3d m_currentTransformation;

	// Identity pose (no translation/rotation)
	RigidTransform3d m_identityTransformation;
};

TEST_F(FixedRepresentationTest, ConstructorTest)
{
	ASSERT_NO_THROW( {FixedRepresentation fixedRepresentation("FixedRepresentation");});
}

TEST_F(FixedRepresentationTest, ResetStateTest)
{
	// Create the rigid body
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	fixedRepresentation->setIsActive(false);
	fixedRepresentation->setIsGravityEnabled(false);
	fixedRepresentation->setInitialPose(m_initialTransformation);
	// Initial = Current = Previous = Final = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getInitialPose().isApprox(m_initialTransformation));

	fixedRepresentation->setCurrentPose(m_currentTransformation);
	// setCurrent is supposed to backup current in previous and set current
	// Therefore it should not affect initial nor final
	// Initial = Final = Previous = m_initialTransformation
	// Current = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getFinalPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	fixedRepresentation->setCurrentPose(m_currentTransformation);
	// setCurrent is supposed to backup current in previous and set current
	// Therefore it should not affect initial nor final
	// Initial = Final = m_initialTransformation
	// Previous = Current = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_FALSE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_FALSE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getFinalPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	fixedRepresentation->afterUpdate(1.0);
	// afterUpdate simply backs up the current into the final
	// Initial = m_initialTransformation
	// Previous = Current = Final = m_initialTransformation
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_currentTransformation));

	std::shared_ptr<Representation> representation = fixedRepresentation;
	// reset the representation (NOT THE FIXED REPRESENTATION, test polymorphism)
	representation->resetState();

	// isActive flag unchanged
	EXPECT_FALSE(fixedRepresentation->isActive());
	// isGravityEnable flag unchanged
	EXPECT_FALSE(fixedRepresentation->isGravityEnabled());
	// The current rigid state should be exactly the initial rigid state
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getFinalPose().isApprox(m_initialTransformation));
	EXPECT_TRUE(fixedRepresentation->getInitialPose().isApprox(m_initialTransformation));
	// The previous rigid state should be exactly the initial rigid state
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(m_initialTransformation));
}

TEST_F(FixedRepresentationTest, SetGetAndDefaultValueTest)
{
	// Create the fixed representation
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	// Get/Set active flag [default = true]
	EXPECT_TRUE(fixedRepresentation->isActive());
	fixedRepresentation->setIsActive(false);
	ASSERT_FALSE(fixedRepresentation->isActive());
	fixedRepresentation->setIsActive(true);
	ASSERT_TRUE(fixedRepresentation->isActive());

	// Get numDof = 0
	ASSERT_EQ(0u, fixedRepresentation->getNumDof());

	// Set/Get isGravityEnabled [default = true]
	EXPECT_TRUE(fixedRepresentation->isGravityEnabled());
	fixedRepresentation->setIsGravityEnabled(false);
	ASSERT_FALSE(fixedRepresentation->isGravityEnabled());
	fixedRepresentation->setIsGravityEnabled(true);
	ASSERT_TRUE(fixedRepresentation->isGravityEnabled());

	// Set/Get current pose [default = no translation, no rotation]
	EXPECT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getFinalPose()));
	fixedRepresentation->setCurrentPose(m_currentTransformation);
	fixedRepresentation->afterUpdate(1.0); // afterUpdate backs up current into final
	ASSERT_TRUE(m_currentTransformation.isApprox(fixedRepresentation->getFinalPose()));
	fixedRepresentation->setCurrentPose(m_identityTransformation);
	fixedRepresentation->afterUpdate(1.0); // afterUpdate backs up current into final
	ASSERT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getFinalPose()));

	// Set/Get initial pose [default = no translation, no rotation]
	EXPECT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getInitialPose()));
	fixedRepresentation->setInitialPose(m_initialTransformation);
	ASSERT_TRUE(m_initialTransformation.isApprox(fixedRepresentation->getInitialPose()));
	fixedRepresentation->setInitialPose(m_identityTransformation);
	ASSERT_TRUE(m_identityTransformation.isApprox(fixedRepresentation->getInitialPose()));
}

TEST_F(FixedRepresentationTest, UpdateTest)
{
	// Create the fixed representation
	std::shared_ptr<FixedRepresentation> fixedRepresentation = std::make_shared<FixedRepresentation>("FixedRepresentation");

	double dt = 1.0;

	// Sets Initial state and reset all other state with initial state
	fixedRepresentation->setInitialPose(m_initialTransformation);
	// Backs up current state into previous state and set the current
	fixedRepresentation->setCurrentPose(m_currentTransformation);

	// Does not do anything
	fixedRepresentation->beforeUpdate(dt);
	// Does not do anything
	fixedRepresentation->update(dt);
	// Backs up current state into final state
	fixedRepresentation->afterUpdate(dt);

	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getPreviousPose()));
	EXPECT_FALSE(fixedRepresentation->getFinalPose().isApprox(fixedRepresentation->getInitialPose()));
	EXPECT_TRUE(fixedRepresentation->getPreviousPose().isApprox(fixedRepresentation->getInitialPose()));
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#include <cassert>
#include "visualizer/vertexArray.hpp"

VertexArray::VertexArray(PrimitiveType primitiveType)
    : vertices(),
      textureCoordinates(),
      colors(),
      mPrimitiveType(primitiveType),
      mTextureID(0),
      mColor(1.0f, 1.0f, 1.0f),
      mHaveColor(false)
{
}

VertexArray::VertexArray(const Color& color, PrimitiveType primitiveType)
    : vertices(),
      textureCoordinates(),
      colors(),
      mPrimitiveType(primitiveType),
      mTextureID(0),
      mColor(color),
      mHaveColor(true)
{
}

void VertexArray::draw() {
  // enable everything
  {
    if (!textureCoordinates.empty()) {
      glEnable(GL_TEXTURE_2D);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glBindTexture(GL_TEXTURE_2D, mTextureID);
      glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates.data());
    }
    if (!vertices.empty()) {
      glEnableClientState(GL_VERTEX_ARRAY);
    }
    if (!colors.empty()) {
      glEnableClientState(GL_COLOR_ARRAY);
      glColorPointer(3, GL_UNSIGNED_BYTE, 0, colors.data());
    }
    if (mHaveColor) {
      glColor3f(mColor.red(), mColor.green(), mColor.blue());
    } else {
      glColor3f(1.0f, 1.0f, 1.0f);
    }
  }
  // draw
  {
    glVertexPointer(3, GL_FLOAT, 0, vertices.data());
    switch (mPrimitiveType) {
    case PrimitiveType::Triangles:
      glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);
      break;
    case PrimitiveType::Lines:
      glDrawArrays(GL_LINES, 0, vertices.size() / 3);
      break;
    default:
      throw std::logic_error("default case");
    }
  }
  // disable everything
  {
    if (!textureCoordinates.empty()) {
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      glDisable(GL_TEXTURE_2D);
    }
    if (!vertices.empty()) {
      glDisableClientState(GL_VERTEX_ARRAY);
    }
    if (!colors.empty()) {
      glDisableClientState(GL_COLOR_ARRAY);
    }
  }
}

void appendV2f(std::vector<float>* vertices, const V2f& vertex) {
  assert(vertices);
  vertices->push_back(vertex.x());
  vertices->push_back(vertex.y());
}

void appendV3f(std::vector<float>* vertices, const V3f& vertex) {
  assert(vertices);
  vertices->push_back(vertex.x());
  vertices->push_back(vertex.y());
  vertices->push_back(vertex.z());
}

void appendRGB(std::vector<GLubyte>* colors, GLubyte r, GLubyte g, GLubyte b) {
  assert(colors);
  colors->push_back(r);
  colors->push_back(g);
  colors->push_back(b);
}

void appendRGB(std::vector<GLubyte>* colors, int r, int g, int b) {
  assert(r >= 0 && r < 256);
  assert(g >= 0 && g < 256);
  assert(b >= 0 && b < 256);
  assert(colors);
  appendRGB(colors,
    static_cast<GLubyte>(r),
    static_cast<GLubyte>(g),
    static_cast<GLubyte>(b));
}
<commit_msg>Fixed compilation error in visualizer/vertexArray.cpp<commit_after>// See LICENSE file for copyright and license details.

#include <cassert>
#include <stdexcept>
#include "visualizer/vertexArray.hpp"

VertexArray::VertexArray(PrimitiveType primitiveType)
    : vertices(),
      textureCoordinates(),
      colors(),
      mPrimitiveType(primitiveType),
      mTextureID(0),
      mColor(1.0f, 1.0f, 1.0f),
      mHaveColor(false)
{
}

VertexArray::VertexArray(const Color& color, PrimitiveType primitiveType)
    : vertices(),
      textureCoordinates(),
      colors(),
      mPrimitiveType(primitiveType),
      mTextureID(0),
      mColor(color),
      mHaveColor(true)
{
}

void VertexArray::draw() {
  // enable everything
  {
    if (!textureCoordinates.empty()) {
      glEnable(GL_TEXTURE_2D);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glBindTexture(GL_TEXTURE_2D, mTextureID);
      glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates.data());
    }
    if (!vertices.empty()) {
      glEnableClientState(GL_VERTEX_ARRAY);
    }
    if (!colors.empty()) {
      glEnableClientState(GL_COLOR_ARRAY);
      glColorPointer(3, GL_UNSIGNED_BYTE, 0, colors.data());
    }
    if (mHaveColor) {
      glColor3f(mColor.red(), mColor.green(), mColor.blue());
    } else {
      glColor3f(1.0f, 1.0f, 1.0f);
    }
  }
  // draw
  {
    glVertexPointer(3, GL_FLOAT, 0, vertices.data());
    switch (mPrimitiveType) {
    case PrimitiveType::Triangles:
      glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);
      break;
    case PrimitiveType::Lines:
      glDrawArrays(GL_LINES, 0, vertices.size() / 3);
      break;
    default:
      throw std::logic_error("default case");
    }
  }
  // disable everything
  {
    if (!textureCoordinates.empty()) {
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      glDisable(GL_TEXTURE_2D);
    }
    if (!vertices.empty()) {
      glDisableClientState(GL_VERTEX_ARRAY);
    }
    if (!colors.empty()) {
      glDisableClientState(GL_COLOR_ARRAY);
    }
  }
}

void appendV2f(std::vector<float>* vertices, const V2f& vertex) {
  assert(vertices);
  vertices->push_back(vertex.x());
  vertices->push_back(vertex.y());
}

void appendV3f(std::vector<float>* vertices, const V3f& vertex) {
  assert(vertices);
  vertices->push_back(vertex.x());
  vertices->push_back(vertex.y());
  vertices->push_back(vertex.z());
}

void appendRGB(std::vector<GLubyte>* colors, GLubyte r, GLubyte g, GLubyte b) {
  assert(colors);
  colors->push_back(r);
  colors->push_back(g);
  colors->push_back(b);
}

void appendRGB(std::vector<GLubyte>* colors, int r, int g, int b) {
  assert(r >= 0 && r < 256);
  assert(g >= 0 && g < 256);
  assert(b >= 0 && b < 256);
  assert(colors);
  appendRGB(colors,
    static_cast<GLubyte>(r),
    static_cast<GLubyte>(g),
    static_cast<GLubyte>(b));
}
<|endoftext|>


<commit_before>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"

class UiMultilineEntry : public UiControl {
	DEFINE_EVENT(onChanged)

  public:
	UiMultilineEntry();
	DEFINE_CONTROL_METHODS()
	void setText(std::string text);
	std::string getText();
	void setReadOnly(bool readOnly);
	bool getReadOnly();
	void append(std::string text);
	~UiMultilineEntry();
	void onDestroy(uiControl *control) override;
};

UiMultilineEntry::~UiMultilineEntry() {
	// printf("UiMultilineEntry %p destroyed with wrapper %p.\n", getHandle(),
	// 	   this);
}

void UiMultilineEntry::onDestroy(uiControl *control) {
	/*
		freeing event callbacks to allow JS to garbage collect this class
		when there are no references to it left in JS code.
	*/
	DISPOSE_EVENT(onChanged);
}
UiMultilineEntry::UiMultilineEntry()
	: UiControl(uiControl(uiNewNonWrappingMultilineEntry())) {}

INHERITS_CONTROL_METHODS(UiMultilineEntry)

IMPLEMENT_EVENT(UiMultilineEntry, uiMultilineEntry, onChanged,
				uiMultilineEntryOnChanged)

void UiMultilineEntry::setText(std::string text) {
	uiMultilineEntrySetText(uiMultilineEntry(getHandle()), text.c_str());
	if (onChangedCallback != NULL) {
		(*onChangedCallback)();
	}
}

std::string UiMultilineEntry::getText() {
	char *char_ptr = uiMultilineEntryText(uiMultilineEntry(getHandle()));
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

void UiMultilineEntry::setReadOnly(bool readOnly) {
	uiMultilineEntrySetReadOnly(uiMultilineEntry(getHandle()), readOnly);
}

bool UiMultilineEntry::getReadOnly() {
	return uiMultilineEntryReadOnly(uiMultilineEntry(getHandle()));
}

void UiMultilineEntry::append(std::string text) {
	uiMultilineEntryAppend(uiMultilineEntry(getHandle()), text.c_str());
}

NBIND_CLASS(UiMultilineEntry) {
	construct<>();
	DECLARE_CHILD_CONTROL_METHODS()
	getset(getText, setText);
	getset(getReadOnly, setReadOnly);
	method(getText);
	method(setText);
	method(getReadOnly);
	method(setReadOnly);
	method(append);
	method(onChanged);
}
<commit_msg>removed macro -> UiMultilineEntry<commit_after>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"

class UiMultilineEntry : public UiControl {
	DEFINE_EVENT(onChanged)

  public:
	UiMultilineEntry();
	void setText(std::string text);
	std::string getText();
	void setReadOnly(bool readOnly);
	bool getReadOnly();
	void append(std::string text);
	~UiMultilineEntry();
	void onDestroy(uiControl *control) override;
};

UiMultilineEntry::~UiMultilineEntry() {
	// printf("UiMultilineEntry %p destroyed with wrapper %p.\n", getHandle(),
	// 	   this);
}

void UiMultilineEntry::onDestroy(uiControl *control) {
	/*
		freeing event callbacks to allow JS to garbage collect this class
		when there are no references to it left in JS code.
	*/
	DISPOSE_EVENT(onChanged);
}
UiMultilineEntry::UiMultilineEntry()
	: UiControl(uiControl(uiNewNonWrappingMultilineEntry())) {}

IMPLEMENT_EVENT(UiMultilineEntry, uiMultilineEntry, onChanged,
				uiMultilineEntryOnChanged)

void UiMultilineEntry::setText(std::string text) {
	uiMultilineEntrySetText(uiMultilineEntry(getHandle()), text.c_str());
	if (onChangedCallback != NULL) {
		(*onChangedCallback)();
	}
}

std::string UiMultilineEntry::getText() {
	char *char_ptr = uiMultilineEntryText(uiMultilineEntry(getHandle()));
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

void UiMultilineEntry::setReadOnly(bool readOnly) {
	uiMultilineEntrySetReadOnly(uiMultilineEntry(getHandle()), readOnly);
}

bool UiMultilineEntry::getReadOnly() {
	return uiMultilineEntryReadOnly(uiMultilineEntry(getHandle()));
}

void UiMultilineEntry::append(std::string text) {
	uiMultilineEntryAppend(uiMultilineEntry(getHandle()), text.c_str());
}

NBIND_CLASS(UiMultilineEntry) {
	inherit(UiControl);
	construct<>();
	getset(getText, setText);
	getset(getReadOnly, setReadOnly);
	method(getText);
	method(setText);
	method(getReadOnly);
	method(setReadOnly);
	method(append);
	method(onChanged);
}
<|endoftext|>