<commit_before>// @(#)root/eve:$Id$
// Author: Matevz Tadel 2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGPack.h"
#include "TGSplitter.h"
#include "TMath.h"

//______________________________________________________________________________
//
// Stack of frames in horizontal (default) or vertical stack.
// The splitters are placed between the neighbouring frames so that
// they can be resized by the user.
// When the whole pack is resized, frames are scaled proportionally to
// their previous size.
//
// When frames are left in pack at destruction time, they will be
// deleted via local-cleanup.

ClassImp(TGPack);

//______________________________________________________________________________
TGPack::TGPack(const TGWindow *p, UInt_t w, UInt_t h, UInt_t options, Pixel_t back) :
   TGCompositeFrame(p, w, h, options, back),
   fVertical     (kTRUE),
   fUseSplitters (kTRUE),
   fSplitterLen  (4),
   fDragOverflow (0),
   fWeightSum(0),
   fNVisible(0)
{
   // Constructor.

   SetCleanup(kLocalCleanup);
}

//______________________________________________________________________________
TGPack::TGPack(TGClient *c, Window_t id, const TGWindow *parent) :
   TGCompositeFrame(c, id, parent),
   fVertical     (kTRUE),
   fUseSplitters (kTRUE),
   fSplitterLen  (4),
   fDragOverflow (0)
{
   // Constructor.

   SetCleanup(kLocalCleanup);
}

//______________________________________________________________________________
TGPack::~TGPack()
{
   // Destructor.
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
Int_t TGPack::GetAvailableLength() const
{
   // Return length of entire frame without splitters.

   Int_t len = fVertical ? GetHeight() : GetWidth();
   len -= fSplitterLen * (fNVisible - 1);

   return len;
}

//______________________________________________________________________________
void TGPack::SetFrameLength(TGFrame* f, Int_t len)
{
   // Set pack-wise length of frame f.

   if (fVertical)
      f->Resize(GetWidth(), len);
   else
      f->Resize(len, GetHeight());
}

//______________________________________________________________________________
void TGPack::SetFramePosition(TGFrame* f, Int_t pos)
{
   // Set pack-wise position of frame f.

   if (fVertical)
      f->Move(0, pos);
   else
      f->Move(pos, 0);
}

//______________________________________________________________________________
void TGPack::CheckSplitterVisibility()
{
   // Check if splitter of first visible frame is hidden.
   // Check if the next following visible splitter is visible.

   TGFrameElementPack *el;
   TIter next(fList);
   Int_t rvf = 0;
   while ((el = (TGFrameElementPack*) next()))
   {
      if (el->fState && el->fSplitFE)
      {
         if (rvf)
         {
            // unmap first slider if necessary
            if ( el->fSplitFE->fState == 0 ) {
               el->fSplitFE->fState = 1;
               el->fSplitFE->fFrame->MapWindow();
            }
         }
         else
         {
            // show slider in next visible frame
            if (el->fSplitFE->fState) {
               el->fSplitFE->fState = 0;
               el->fSplitFE->fFrame->UnmapWindow();
            }
         }
         ++rvf;
      }
   }
}

//______________________________________________________________________________
void TGPack::ResizeExistingFrames()
{
   // Resize (shrink or expand) existing frames by amount in total.

   if (fList->IsEmpty())
      return;

   // get unitsize
   Int_t nflen  = GetAvailableLength();
   Float_t unit = Float_t(nflen)/fWeightSum;

   // set frame sizes
   Int_t sumFrames = 0;
   Int_t frameLength = 0;
   {
      TGFrameElementPack *el;
      TIter next(fList);
      while ((el = (TGFrameElementPack*) next()))
      {
         if (el->fState && el->fWeight)
         {
            frameLength = TMath::Nint( unit*(el->fWeight));
            SetFrameLength(el->fFrame, frameLength);
            sumFrames += frameLength;
         }
      }
   }

   // redistribute the remain
   {
      // printf("available %d total %d \n", nflen, sumFrames);
      Int_t remain =  nflen-sumFrames;
      Int_t step = TMath::Sign(1, remain);
      TGFrameElementPack *el;
      TIter next(fList);
      while ((el = (TGFrameElementPack*) next()) && remain)
      {
         if (el->fState &&  el->fWeight)
         {
            Int_t l = GetFrameLength(el->fFrame) + step;
            if (l > 0)
            {
               SetFrameLength(el->fFrame, l);
               remain -= step;
            }
         }
      }
   }
   RefitFramesToPack();
}

//______________________________________________________________________________
void TGPack::RefitFramesToPack()
{
   // Refit existing frames to pack size.

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next()))
   {
      if (fVertical)
         el->fFrame->Resize(GetWidth(), el->fFrame->GetHeight());
      else
         el->fFrame->Resize(el->fFrame->GetWidth(), GetHeight());
   }
}

//______________________________________________________________________________
void TGPack::FindFrames(TGFrame* splitter, TGFrameElementPack*& f0, TGFrameElementPack*& f1) const
{
   // Find frames around splitter and return them f0 (previous) and f1 (next).

   TGFrameElementPack *el;
   TIter next(fList);

   while ((el = (TGFrameElementPack *) next()))
   {
      if (el->fFrame == splitter)
         break;
      f0 = el;
   }
   f1 = (TGFrameElementPack *) next();
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::AddFrameInternal(TGFrame* f, TGLayoutHints* l, Float_t weight)
{
   // Add frame f at the end.
   // LayoutHints are ignored in TGPack.

   // add splitter
   TGFrameElementPack *sf = 0;
   if (fUseSplitters) {
      TGSplitter* s = 0;
      if (fVertical)
         s = new TGHSplitter(this, GetWidth(), fSplitterLen, kTRUE);
      else
         s = new TGVSplitter(this, fSplitterLen, GetHeight(), kTRUE);
      s->Connect("Moved(Int_t)",  "TGPack", this, "HandleSplitterResize(Int_t)");
      s->Connect("DragStarted()", "TGPack", this, "HandleSplitterStart()");

      sf = new TGFrameElementPack(s, l ? l : fgDefaultHints, 0);
      fList->Add(sf);
      // in case of recusive cleanup, propagate cleanup setting to all
      // child composite frames
      if (fMustCleanup == kDeepCleanup)
         s->SetCleanup(kDeepCleanup);
      s->MapWindow();
   }

   // instread TGCopositeFrame::AddFrame
   TGFrameElementPack *el = new TGFrameElementPack(f, l ? l : fgDefaultHints, weight);
   el->fSplitFE = sf;
   fList->Add(el);

   // in case of recusive cleanup, propagate cleanup setting to all
   // child composite frames
   if (fMustCleanup == kDeepCleanup)
      f->SetCleanup(kDeepCleanup);
   f->MapWindow();

   fNVisible ++;
   fWeightSum += weight;

   CheckSplitterVisibility();
   ResizeExistingFrames();
}

//______________________________________________________________________________
void TGPack::AddFrameWithWeight(TGFrame* f, TGLayoutHints *l, Float_t weight)
{
   // Add frame f at the end with given weight.
   // LayoutHints are ignored in TGPack.

   AddFrameInternal(f, l, weight);
   Layout();
}

//______________________________________________________________________________
void TGPack::AddFrame(TGFrame* f, TGLayoutHints *l)
{
   // Add frame f at the end with default weight.
   // LayoutHints are ignored in TGPack.

   AddFrameInternal(f, l, 1);
   Layout();
}

//______________________________________________________________________________
void TGPack::RemoveFrameInternal(TGFrame* f)
{
   // Remove frame f.

   TGFrameElementPack *el = (TGFrameElementPack*)FindFrameElement(f);

   if (!el || el->fState == 0 ) return;

   if (fUseSplitters )
   {
      TGFrame* splitter = el->fSplitFE->fFrame;
      splitter->UnmapWindow();
      TGCompositeFrame::RemoveFrame(splitter);
      // This is needed so that splitter window gets destroyed on server.
      splitter->ReparentWindow(fClient->GetDefaultRoot());
      delete splitter;
   }
   f->UnmapWindow();
   TGCompositeFrame::RemoveFrame(f);

   fNVisible --;
   fWeightSum -= el->fWeight;

   CheckSplitterVisibility();
   ResizeExistingFrames();
}

//______________________________________________________________________________
void TGPack::DeleteFrame(TGFrame* f)
{
   // Remove frame f and refit existing frames to pack size.
   // Frame is deleted.

   RemoveFrameInternal(f);
   delete f;
   Layout();
}

//______________________________________________________________________________
void TGPack::RemoveFrame(TGFrame* f)
{
   // Remove frame f and refit existing frames to pack size.
   // Frame is not deleted.

   RemoveFrameInternal(f);
   Layout();
}

//______________________________________________________________________________
void TGPack::Dump() const
{
   // Print sub frame info.

   printf("--------------------------------------------------------------\n");
   Int_t cnt = 0;
   TGFrameElementPack *el;
   TIter next(fList);
   while ((el = (TGFrameElementPack *) next()))
   {
      printf("idx[%d] visible(%d) %s  \n",cnt, el->fState, el->fFrame->GetName());
      cnt++;
   }
   printf("--------------------------------------------------------------\n");
}

//______________________________________________________________________________
void TGPack::ShowFrame(TGFrame* f)
{
   // Show sub frame.
   // Virtual from TGCompositeFrame.

   TGFrameElementPack *el = (TGFrameElementPack*)FindFrameElement(f);
   if (el)
   {
      //show
      el->fState = 1;
      el->fFrame->MapWindow();

      // show splitter
      if (fUseSplitters)
      {
         el->fSplitFE->fFrame->MapWindow();
         el->fSplitFE->fState = 1;
      }

      // Dump();
      fNVisible++;
      fWeightSum += el->fWeight;

      CheckSplitterVisibility();
      ResizeExistingFrames();
      Layout();
   }
}

//______________________________________________________________________________
void TGPack::HideFrame(TGFrame* f)
{
   // Hide sub frame.
   // Virtual from TGCompositeFrame.

   TGFrameElementPack *el = (TGFrameElementPack*) FindFrameElement(f);
   if (el)
   {
      // hide real frame
      el->fState = 0;
      el->fFrame->UnmapWindow();

      // hide splitter
      if (fUseSplitters)
      {
         el->fSplitFE->fFrame->UnmapWindow();
         el->fSplitFE->fState = 0;
      }

      // Dump();
      fNVisible--;
      fWeightSum -= el->fWeight;

      CheckSplitterVisibility();
      ResizeExistingFrames();
      Layout();
   }
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::MapSubwindows()
{
   // Virtual method of TGcompositeFrame.
   // Map all sub windows that are part of the composite frame.

   if (!fMapSubwindows) {
      return;
   }

   if (!fList) return;

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next())) {
      if (el->fFrame && el->fState) {
         el->fFrame->MapWindow();
         el->fFrame->MapSubwindows();
         TGFrameElement *fe = el->fFrame->GetFrameElement();
         if (fe) fe->fState |= kIsVisible;
      }
   }
}

//______________________________________________________________________________
void TGPack::Resize(UInt_t w, UInt_t h)
{
   // Resize the pack.
   // Contents is resized proportionally.

   if (w == fWidth && h == fHeight) return;

   fWidth  = w;
   fHeight = h;
   TGWindow::Resize(fWidth, fHeight);

   ResizeExistingFrames();

   Layout();
}

//______________________________________________________________________________
void TGPack::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Move and resize the pack.

   TGCompositeFrame::Move(x, y);
   Resize(w, h);
}

//______________________________________________________________________________
void TGPack::Layout()
{
   // Reposition the frames so that they fit correctly.
   // LayoutHints are ignored.

   Int_t pos = 0;

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next()))
   {
      if (el->fState)
      {
         SetFramePosition(el->fFrame, pos);
         pos += GetFrameLength(el->fFrame);
         el->fFrame->Layout();
      }
   }
}

//______________________________________________________________________________
void TGPack::EqualizeFrames()
{
   // Refit existing frames so that their lengths are equal.

   if (fList->IsEmpty())
      return;

   fWeightSum = 0;
   TGFrameElementPack *el;
   TIter next(fList);
   while ((el = (TGFrameElementPack *) next()))
   {
      el->fWeight = 1;
      if (el->fState)
         fWeightSum ++;
   }

   ResizeExistingFrames();
   Layout();
}

//______________________________________________________________________________
void TGPack::HandleSplitterStart()
{
   // Called when splitter drag starts.

   fDragOverflow = 0;
}

//______________________________________________________________________________
void TGPack::HandleSplitterResize(Int_t delta)
{
   // Handle resize events from splitters.

   Int_t available = GetAvailableLength();
   Int_t min_dec = - (available + fNVisible*2 -1);
   if (delta <  min_dec)
      delta = min_dec;

   TGSplitter *s = dynamic_cast<TGSplitter*>((TGFrame*) gTQSender);

   TGFrameElementPack *f0=0, *f1=0;
   FindFrames(s, f0, f1);

   if (fDragOverflow < 0)
   {
      fDragOverflow += delta;
      if (fDragOverflow > 0) {
         delta = fDragOverflow;
         fDragOverflow = 0;
      } else {
         return;
      }
   }
   else if (fDragOverflow > 0)
   {
      fDragOverflow += delta;
      if (fDragOverflow < 0) {
         delta = fDragOverflow;
         fDragOverflow = 0;
      } else {
         return;
      }
   }

   Int_t l0 = GetFrameLength(f0->fFrame);
   Int_t l1 = GetFrameLength(f1->fFrame);
   if (delta < 0)
   {
      if (l0 - 1 < -delta)
      {
         fDragOverflow += delta + l0 - 1;
         delta = -l0 + 1;
      }
   }
   else
   {
      if (l1 - 1 < delta)
      {
         fDragOverflow += delta - l1 + 1;
         delta = l1 - 1;
      }
   }
   l0 += delta;
   l1 -= delta;
   SetFrameLength(f0->fFrame, l0);
   SetFrameLength(f1->fFrame, l1);
   Float_t weightDelta = Float_t(delta)/available;
   weightDelta *= fWeightSum;
   f0->fWeight += weightDelta;
   f1->fWeight -= weightDelta;

   ResizeExistingFrames();
   Layout();
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::SetVertical(Bool_t x)
{
   // Sets the vertical flag and reformats the back to new stacking
   // direction.

   if (x == fVertical)
      return;

   TList list;
   while ( ! fList->IsEmpty())
   {
      TGFrame* f = ((TGFrameElement*) fList->First())->fFrame;
      RemoveFrameInternal(f);
      list.Add(f);
   }
   fVertical = x;
   while ( ! list.IsEmpty())
   {
      TGFrame* f = (TGFrame*) list.First();
      AddFrameInternal(f);
      list.RemoveFirst();
   }
   Layout();
}
<commit_msg>Form Alja: - Fix a mistake in TGPack dicovered by running valgrind<commit_after>// @(#)root/eve:$Id$
// Author: Matevz Tadel 2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGPack.h"
#include "TGSplitter.h"
#include "TMath.h"

//______________________________________________________________________________
//
// Stack of frames in horizontal (default) or vertical stack.
// The splitters are placed between the neighbouring frames so that
// they can be resized by the user.
// When the whole pack is resized, frames are scaled proportionally to
// their previous size.
//
// When frames are left in pack at destruction time, they will be
// deleted via local-cleanup.

ClassImp(TGPack);

//______________________________________________________________________________
TGPack::TGPack(const TGWindow *p, UInt_t w, UInt_t h, UInt_t options, Pixel_t back) :
   TGCompositeFrame(p, w, h, options, back),
   fVertical     (kTRUE),
   fUseSplitters (kTRUE),
   fSplitterLen  (4),
   fDragOverflow (0),
   fWeightSum(0),
   fNVisible(0)
{
   // Constructor.

   SetCleanup(kLocalCleanup);
}

//______________________________________________________________________________
TGPack::TGPack(TGClient *c, Window_t id, const TGWindow *parent) :
   TGCompositeFrame(c, id, parent),
   fVertical     (kTRUE),
   fUseSplitters (kTRUE),
   fSplitterLen  (4),
   fDragOverflow (0)
{
   // Constructor.

   SetCleanup(kLocalCleanup);
}

//______________________________________________________________________________
TGPack::~TGPack()
{
   // Destructor.
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
Int_t TGPack::GetAvailableLength() const
{
   // Return length of entire frame without splitters.

   Int_t len = fVertical ? GetHeight() : GetWidth();
   len -= fSplitterLen * (fNVisible - 1);

   return len;
}

//______________________________________________________________________________
void TGPack::SetFrameLength(TGFrame* f, Int_t len)
{
   // Set pack-wise length of frame f.

   if (fVertical)
      f->Resize(GetWidth(), len);
   else
      f->Resize(len, GetHeight());
}

//______________________________________________________________________________
void TGPack::SetFramePosition(TGFrame* f, Int_t pos)
{
   // Set pack-wise position of frame f.

   if (fVertical)
      f->Move(0, pos);
   else
      f->Move(pos, 0);
}

//______________________________________________________________________________
void TGPack::CheckSplitterVisibility()
{
   // Check if splitter of first visible frame is hidden.
   // Check if the next following visible splitter is visible.

   TGFrameElementPack *el;
   TIter next(fList);
   Int_t rvf = 0;
   while ((el = (TGFrameElementPack*) next()))
   {
      if (el->fState && el->fSplitFE)
      {
         if (rvf)
         {
            // unmap first slider if necessary
            if ( el->fSplitFE->fState == 0 ) {
               el->fSplitFE->fState = 1;
               el->fSplitFE->fFrame->MapWindow();
            }
         }
         else
         {
            // show slider in next visible frame
            if (el->fSplitFE->fState) {
               el->fSplitFE->fState = 0;
               el->fSplitFE->fFrame->UnmapWindow();
            }
         }
         ++rvf;
      }
   }
}

//______________________________________________________________________________
void TGPack::ResizeExistingFrames()
{
   // Resize (shrink or expand) existing frames by amount in total.

   if (fList->IsEmpty())
      return;

   // get unitsize
   Int_t nflen  = GetAvailableLength();
   Float_t unit = Float_t(nflen)/fWeightSum;

   // set frame sizes
   Int_t sumFrames = 0;
   Int_t frameLength = 0;
   {
      TGFrameElementPack *el;
      TIter next(fList);
      while ((el = (TGFrameElementPack*) next()))
      {
         if (el->fState && el->fWeight)
         {
            frameLength = TMath::Nint( unit*(el->fWeight));
            SetFrameLength(el->fFrame, frameLength);
            sumFrames += frameLength;
         }
      }
   }

   // redistribute the remain
   {
      // printf("available %d total %d \n", nflen, sumFrames);
      Int_t remain =  nflen-sumFrames;
      Int_t step = TMath::Sign(1, remain);
      TGFrameElementPack *el;
      TIter next(fList);
      while ((el = (TGFrameElementPack*) next()) && remain)
      {
         if (el->fState &&  el->fWeight)
         {
            Int_t l = GetFrameLength(el->fFrame) + step;
            if (l > 0)
            {
               SetFrameLength(el->fFrame, l);
               remain -= step;
            }
         }
      }
   }
   RefitFramesToPack();
}

//______________________________________________________________________________
void TGPack::RefitFramesToPack()
{
   // Refit existing frames to pack size.

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next()))
   {
      if (fVertical)
         el->fFrame->Resize(GetWidth(), el->fFrame->GetHeight());
      else
         el->fFrame->Resize(el->fFrame->GetWidth(), GetHeight());
   }
}

//______________________________________________________________________________
void TGPack::FindFrames(TGFrame* splitter, TGFrameElementPack*& f0, TGFrameElementPack*& f1) const
{
   // Find frames around splitter and return them f0 (previous) and f1 (next).

   TGFrameElementPack *el;
   TIter next(fList);

   while ((el = (TGFrameElementPack *) next()))
   {
      if (el->fFrame == splitter)
         break;
      f0 = el;
   }
   f1 = (TGFrameElementPack *) next();
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::AddFrameInternal(TGFrame* f, TGLayoutHints* l, Float_t weight)
{
   // Add frame f at the end.
   // LayoutHints are ignored in TGPack.

   // add splitter
   TGFrameElementPack *sf = 0;
   if (fUseSplitters) {
      TGSplitter* s = 0;
      if (fVertical)
         s = new TGHSplitter(this, GetWidth(), fSplitterLen, kTRUE);
      else
         s = new TGVSplitter(this, fSplitterLen, GetHeight(), kTRUE);
      s->Connect("Moved(Int_t)",  "TGPack", this, "HandleSplitterResize(Int_t)");
      s->Connect("DragStarted()", "TGPack", this, "HandleSplitterStart()");

      sf = new TGFrameElementPack(s, l ? l : fgDefaultHints, 0);
      fList->Add(sf);
      // in case of recusive cleanup, propagate cleanup setting to all
      // child composite frames
      if (fMustCleanup == kDeepCleanup)
         s->SetCleanup(kDeepCleanup);
      s->MapWindow();
   }

   // instread TGCopositeFrame::AddFrame
   TGFrameElementPack *el = new TGFrameElementPack(f, l ? l : fgDefaultHints, weight);
   el->fSplitFE = sf;
   fList->Add(el);

   // in case of recusive cleanup, propagate cleanup setting to all
   // child composite frames
   if (fMustCleanup == kDeepCleanup)
      f->SetCleanup(kDeepCleanup);
   f->MapWindow();

   fNVisible ++;
   fWeightSum += weight;

   CheckSplitterVisibility();
   ResizeExistingFrames();
}

//______________________________________________________________________________
void TGPack::AddFrameWithWeight(TGFrame* f, TGLayoutHints *l, Float_t weight)
{
   // Add frame f at the end with given weight.
   // LayoutHints are ignored in TGPack.

   AddFrameInternal(f, l, weight);
   Layout();
}

//______________________________________________________________________________
void TGPack::AddFrame(TGFrame* f, TGLayoutHints *l)
{
   // Add frame f at the end with default weight.
   // LayoutHints are ignored in TGPack.

   AddFrameInternal(f, l, 1);
   Layout();
}

//______________________________________________________________________________
void TGPack::RemoveFrameInternal(TGFrame* f)
{
   // Remove frame f.

   TGFrameElementPack *el = (TGFrameElementPack*)FindFrameElement(f);

   if (!el || el->fState == 0 ) return;

   if (fUseSplitters )
   {
      TGFrame* splitter = el->fSplitFE->fFrame;
      splitter->UnmapWindow();
      TGCompositeFrame::RemoveFrame(splitter);
      // This is needed so that splitter window gets destroyed on server.
      splitter->ReparentWindow(fClient->GetDefaultRoot());
      delete splitter;
   }
   f->UnmapWindow();

   fWeightSum -= el->fWeight;
   fNVisible --;
   TGCompositeFrame::RemoveFrame(f);

   CheckSplitterVisibility();
   ResizeExistingFrames();
}

//______________________________________________________________________________
void TGPack::DeleteFrame(TGFrame* f)
{
   // Remove frame f and refit existing frames to pack size.
   // Frame is deleted.

   RemoveFrameInternal(f);
   delete f;
   Layout();
}

//______________________________________________________________________________
void TGPack::RemoveFrame(TGFrame* f)
{
   // Remove frame f and refit existing frames to pack size.
   // Frame is not deleted.

   RemoveFrameInternal(f);
   Layout();
}

//______________________________________________________________________________
void TGPack::Dump() const
{
   // Print sub frame info.

   printf("--------------------------------------------------------------\n");
   Int_t cnt = 0;
   TGFrameElementPack *el;
   TIter next(fList);
   while ((el = (TGFrameElementPack *) next()))
   {
      printf("idx[%d] visible(%d) %s  \n",cnt, el->fState, el->fFrame->GetName());
      cnt++;
   }
   printf("--------------------------------------------------------------\n");
}

//______________________________________________________________________________
void TGPack::ShowFrame(TGFrame* f)
{
   // Show sub frame.
   // Virtual from TGCompositeFrame.

   TGFrameElementPack *el = (TGFrameElementPack*)FindFrameElement(f);
   if (el)
   {
      //show
      el->fState = 1;
      el->fFrame->MapWindow();

      // show splitter
      if (fUseSplitters)
      {
         el->fSplitFE->fFrame->MapWindow();
         el->fSplitFE->fState = 1;
      }

      // Dump();
      fNVisible++;
      fWeightSum += el->fWeight;

      CheckSplitterVisibility();
      ResizeExistingFrames();
      Layout();
   }
}

//______________________________________________________________________________
void TGPack::HideFrame(TGFrame* f)
{
   // Hide sub frame.
   // Virtual from TGCompositeFrame.

   TGFrameElementPack *el = (TGFrameElementPack*) FindFrameElement(f);
   if (el)
   {
      // hide real frame
      el->fState = 0;
      el->fFrame->UnmapWindow();

      // hide splitter
      if (fUseSplitters)
      {
         el->fSplitFE->fFrame->UnmapWindow();
         el->fSplitFE->fState = 0;
      }

      // Dump();
      fNVisible--;
      fWeightSum -= el->fWeight;

      CheckSplitterVisibility();
      ResizeExistingFrames();
      Layout();
   }
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::MapSubwindows()
{
   // Virtual method of TGcompositeFrame.
   // Map all sub windows that are part of the composite frame.

   if (!fMapSubwindows) {
      return;
   }

   if (!fList) return;

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next())) {
      if (el->fFrame && el->fState) {
         el->fFrame->MapWindow();
         el->fFrame->MapSubwindows();
         TGFrameElement *fe = el->fFrame->GetFrameElement();
         if (fe) fe->fState |= kIsVisible;
      }
   }
}

//______________________________________________________________________________
void TGPack::Resize(UInt_t w, UInt_t h)
{
   // Resize the pack.
   // Contents is resized proportionally.

   if (w == fWidth && h == fHeight) return;

   fWidth  = w;
   fHeight = h;
   TGWindow::Resize(fWidth, fHeight);

   ResizeExistingFrames();

   Layout();
}

//______________________________________________________________________________
void TGPack::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Move and resize the pack.

   TGCompositeFrame::Move(x, y);
   Resize(w, h);
}

//______________________________________________________________________________
void TGPack::Layout()
{
   // Reposition the frames so that they fit correctly.
   // LayoutHints are ignored.

   Int_t pos = 0;

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next()))
   {
      if (el->fState)
      {
         SetFramePosition(el->fFrame, pos);
         pos += GetFrameLength(el->fFrame);
         el->fFrame->Layout();
      }
   }
}

//______________________________________________________________________________
void TGPack::EqualizeFrames()
{
   // Refit existing frames so that their lengths are equal.

   if (fList->IsEmpty())
      return;

   fWeightSum = 0;
   TGFrameElementPack *el;
   TIter next(fList);
   while ((el = (TGFrameElementPack *) next()))
   {
      el->fWeight = 1;
      if (el->fState)
         fWeightSum ++;
   }

   ResizeExistingFrames();
   Layout();
}

//______________________________________________________________________________
void TGPack::HandleSplitterStart()
{
   // Called when splitter drag starts.

   fDragOverflow = 0;
}

//______________________________________________________________________________
void TGPack::HandleSplitterResize(Int_t delta)
{
   // Handle resize events from splitters.

   Int_t available = GetAvailableLength();
   Int_t min_dec = - (available + fNVisible*2 -1);
   if (delta <  min_dec)
      delta = min_dec;

   TGSplitter *s = dynamic_cast<TGSplitter*>((TGFrame*) gTQSender);

   TGFrameElementPack *f0=0, *f1=0;
   FindFrames(s, f0, f1);

   if (fDragOverflow < 0)
   {
      fDragOverflow += delta;
      if (fDragOverflow > 0) {
         delta = fDragOverflow;
         fDragOverflow = 0;
      } else {
         return;
      }
   }
   else if (fDragOverflow > 0)
   {
      fDragOverflow += delta;
      if (fDragOverflow < 0) {
         delta = fDragOverflow;
         fDragOverflow = 0;
      } else {
         return;
      }
   }

   Int_t l0 = GetFrameLength(f0->fFrame);
   Int_t l1 = GetFrameLength(f1->fFrame);
   if (delta < 0)
   {
      if (l0 - 1 < -delta)
      {
         fDragOverflow += delta + l0 - 1;
         delta = -l0 + 1;
      }
   }
   else
   {
      if (l1 - 1 < delta)
      {
         fDragOverflow += delta - l1 + 1;
         delta = l1 - 1;
      }
   }
   l0 += delta;
   l1 -= delta;
   SetFrameLength(f0->fFrame, l0);
   SetFrameLength(f1->fFrame, l1);
   Float_t weightDelta = Float_t(delta)/available;
   weightDelta *= fWeightSum;
   f0->fWeight += weightDelta;
   f1->fWeight -= weightDelta;

   ResizeExistingFrames();
   Layout();
}

//------------------------------------------------------------------------------

//______________________________________________________________________________
void TGPack::SetVertical(Bool_t x)
{
   // Sets the vertical flag and reformats the back to new stacking
   // direction.

   if (x == fVertical)
      return;

   TList list;
   while ( ! fList->IsEmpty())
   {
      TGFrame* f = ((TGFrameElement*) fList->First())->fFrame;
      RemoveFrameInternal(f);
      list.Add(f);
   }
   fVertical = x;
   while ( ! list.IsEmpty())
   {
      TGFrame* f = (TGFrame*) list.First();
      AddFrameInternal(f);
      list.RemoveFirst();
   }
   Layout();
}
<|endoftext|>


<commit_before>/**
 * @file Logger.cpp
 * Logger class implementation
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "core/logging/LoggerConfiguration.h"
#include <algorithm>
#include <vector>
#include <queue>
#include <memory>
#include <map>
#include <string>

#include "core/Core.h"
#include "utils/StringUtils.h"

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/null_sink.h"

namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace core {
namespace logging {

const char* LoggerConfiguration::spdlog_default_pattern = "[%Y-%m-%ll %H:%M:%S.%e] [%n] [%l] %v";

std::vector<std::string> LoggerProperties::get_keys_of_type(const std::string &type) {
  std::vector<std::string> appenders;
  std::string prefix = type + ".";
  for (auto const & entry : properties_) {
    if (entry.first.rfind(prefix, 0) == 0 && entry.first.find(".", prefix.length() + 1) == std::string::npos) {
      appenders.push_back(entry.first);
    }
  }
  return appenders;
}

LoggerConfiguration::LoggerConfiguration()
    : root_namespace_(create_default_root()),
      loggers(std::vector<std::shared_ptr<LoggerImpl>>()),
      formatter_(std::make_shared<spdlog::pattern_formatter>(spdlog_default_pattern)) {
  logger_ = std::shared_ptr<LoggerImpl>(new LoggerImpl(core::getClassName<LoggerConfiguration>(), get_logger(nullptr, root_namespace_, core::getClassName<LoggerConfiguration>(), formatter_)));
  loggers.push_back(logger_);
}

void LoggerConfiguration::initialize(const std::shared_ptr<LoggerProperties> &logger_properties) {
  std::lock_guard<std::mutex> lock(mutex);
  root_namespace_ = initialize_namespaces(logger_properties);
  std::string spdlog_pattern;
  if (!logger_properties->get("spdlog.pattern", spdlog_pattern)) {
    spdlog_pattern = spdlog_default_pattern;
  }
  formatter_ = std::make_shared<spdlog::pattern_formatter>(spdlog_pattern);
  std::map<std::string, std::shared_ptr<spdlog::logger>> spdloggers;
  for (auto const & logger_impl : loggers) {
    std::shared_ptr<spdlog::logger> spdlogger;
    auto it = spdloggers.find(logger_impl->name);
    if (it == spdloggers.end()) {
      spdlogger = get_logger(logger_, root_namespace_, logger_impl->name, formatter_, true);
      spdloggers[logger_impl->name] = spdlogger;
    } else {
      spdlogger = it->second;
    }
    logger_impl->set_delegate(spdlogger);
  }
  logger_->log_debug("Set following pattern on loggers: %s", spdlog_pattern);
}

std::shared_ptr<Logger> LoggerConfiguration::getLogger(const std::string &name) {
  std::lock_guard<std::mutex> lock(mutex);
  std::shared_ptr<LoggerImpl> result = std::make_shared<LoggerImpl>(name, get_logger(logger_, root_namespace_, name, formatter_));
  loggers.push_back(result);
  return result;
}

std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration::initialize_namespaces(const std::shared_ptr<LoggerProperties> &logger_properties) {
  std::map<std::string, std::shared_ptr<spdlog::sinks::sink>> sink_map = logger_properties->initial_sinks();

  std::string appender_type = "appender";
  for (auto const & appender_key : logger_properties->get_keys_of_type(appender_type)) {
    std::string appender_name = appender_key.substr(appender_type.length() + 1);
    std::string appender_type;
    if (!logger_properties->get(appender_key, appender_type)) {
      appender_type = "stderr";
    }
    std::transform(appender_type.begin(), appender_type.end(), appender_type.begin(), ::tolower);

    if ("nullappender" == appender_type || "null appender" == appender_type || "null" == appender_type) {
      sink_map[appender_name] = std::make_shared<spdlog::sinks::null_sink_st>();
    } else if ("rollingappender" == appender_type || "rolling appender" == appender_type || "rolling" == appender_type) {
      std::string file_name = "";
      if (!logger_properties->get(appender_key + ".file_name", file_name)) {
        file_name = "minifi-app.log";
      }

      int max_files = 3;
      std::string max_files_str = "";
      if (logger_properties->get(appender_key + ".max_files", max_files_str)) {
        try {
          max_files = std::stoi(max_files_str);
        } catch (const std::invalid_argument &ia) {
        } catch (const std::out_of_range &oor) {
        }
      }

      int max_file_size = 5 * 1024 * 1024;
      std::string max_file_size_str = "";
      if (logger_properties->get(appender_key + ".max_file_size", max_file_size_str)) {
        try {
          max_file_size = std::stoi(max_file_size_str);
        } catch (const std::invalid_argument &ia) {
        } catch (const std::out_of_range &oor) {
        }
      }
      sink_map[appender_name] = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_name, max_file_size, max_files);
    } else if ("stdout" == appender_type) {
      sink_map[appender_name] = spdlog::sinks::stdout_sink_mt::instance();
    } else {
      sink_map[appender_name] = spdlog::sinks::stderr_sink_mt::instance();
    }
  }

  std::shared_ptr<internal::LoggerNamespace> root_namespace = std::make_shared<internal::LoggerNamespace>();
  std::string logger_type = "logger";
  for (auto const & logger_key : logger_properties->get_keys_of_type(logger_type)) {
    std::string logger_def;
    if (!logger_properties->get(logger_key, logger_def)) {
      continue;
    }
    bool first = true;
    spdlog::level::level_enum level = spdlog::level::info;
    std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks;
    for (auto const & segment : utils::StringUtils::split(logger_def, ",")) {
      std::string level_name = utils::StringUtils::trim(segment);
      if (first) {
        first = false;
        std::transform(level_name.begin(), level_name.end(), level_name.begin(), ::tolower);
        if ("trace" == level_name) {
          level = spdlog::level::trace;
        } else if ("debug" == level_name) {
          level = spdlog::level::debug;
        } else if ("warn" == level_name) {
          level = spdlog::level::warn;
        } else if ("critical" == level_name) {
          level = spdlog::level::critical;
        } else if ("error" == level_name) {
          level = spdlog::level::err;
        } else if ("off" == level_name) {
          level = spdlog::level::off;
        }
      } else {
        sinks.push_back(sink_map[level_name]);
      }
    }
    std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace;
    if (logger_key != "logger.root") {
      for (auto const & name : utils::StringUtils::split(logger_key.substr(logger_type.length() + 1, logger_key.length() - logger_type.length()), "::")) {
        auto child_pair = current_namespace->children.find(name);
        std::shared_ptr<internal::LoggerNamespace> child;
        if (child_pair == current_namespace->children.end()) {
          child = std::make_shared<internal::LoggerNamespace>();
          current_namespace->children[name] = child;
        } else {
          child = child_pair->second;
        }
        current_namespace = child;
      }
    }
    current_namespace->level = level;
    current_namespace->has_level = true;
    current_namespace->sinks = sinks;
  }
  return root_namespace;
}

std::shared_ptr<spdlog::logger> LoggerConfiguration::get_logger(std::shared_ptr<Logger> logger, const std::shared_ptr<internal::LoggerNamespace> &root_namespace, const std::string &name,
                                                                std::shared_ptr<spdlog::formatter> formatter, bool remove_if_present) {
  std::shared_ptr<spdlog::logger> spdlogger = spdlog::get(name);
  if (spdlogger) {
    if (remove_if_present) {
      spdlog::drop(name);
    } else {
      return spdlogger;
    }
  }
  std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace;
  std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks = root_namespace->sinks;
  spdlog::level::level_enum level = root_namespace->level;
  std::string current_namespace_str = "";
  std::string sink_namespace_str = "root";
  std::string level_namespace_str = "root";
  for (auto const & name_segment : utils::StringUtils::split(name, "::")) {
    current_namespace_str += name_segment;
    auto child_pair = current_namespace->children.find(name_segment);
    if (child_pair == current_namespace->children.end()) {
      break;
    }
    current_namespace = child_pair->second;
    if (current_namespace->sinks.size() > 0) {
      sinks = current_namespace->sinks;
      sink_namespace_str = current_namespace_str;
    }
    if (current_namespace->has_level) {
      level = current_namespace->level;
      level_namespace_str = current_namespace_str;
    }
    current_namespace_str += "::";
  }
  if (logger != nullptr) {
    logger->log_debug("%s logger got sinks from namespace %s and level %s from namespace %s", name, sink_namespace_str, spdlog::level::level_names[level], level_namespace_str);
  }
  spdlogger = std::make_shared<spdlog::logger>(name, begin(sinks), end(sinks));
  spdlogger->set_level(level);
  spdlogger->set_formatter(formatter);
  spdlogger->flush_on(std::max(spdlog::level::info, current_namespace->level));
  try {
    spdlog::register_logger(spdlogger);
  } catch (const spdlog::spdlog_ex &ex) {
    // Ignore as someone else beat us to registration, we should get the one they made below
  }
  return spdlog::get(name);
}

std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration::create_default_root() {
  std::shared_ptr<internal::LoggerNamespace> result = std::make_shared<internal::LoggerNamespace>();
  result->sinks = std::vector<std::shared_ptr<spdlog::sinks::sink>>();
  result->sinks.push_back(spdlog::sinks::stderr_sink_mt::instance());
  result->level = spdlog::level::info;
  return result;
}

} /* namespace logging */
} /* namespace core */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
<commit_msg>MINIFICPP-337: make default log directory as logs<commit_after>/**
 * @file Logger.cpp
 * Logger class implementation
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "core/logging/LoggerConfiguration.h"
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <memory>
#include <map>
#include <string>

#include "core/Core.h"
#include "utils/StringUtils.h"

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/null_sink.h"

namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace core {
namespace logging {

const char* LoggerConfiguration::spdlog_default_pattern = "[%Y-%m-%ll %H:%M:%S.%e] [%n] [%l] %v";

std::vector<std::string> LoggerProperties::get_keys_of_type(const std::string &type) {
  std::vector<std::string> appenders;
  std::string prefix = type + ".";
  for (auto const & entry : properties_) {
    if (entry.first.rfind(prefix, 0) == 0 && entry.first.find(".", prefix.length() + 1) == std::string::npos) {
      appenders.push_back(entry.first);
    }
  }
  return appenders;
}

LoggerConfiguration::LoggerConfiguration()
    : root_namespace_(create_default_root()),
      loggers(std::vector<std::shared_ptr<LoggerImpl>>()),
      formatter_(std::make_shared<spdlog::pattern_formatter>(spdlog_default_pattern)) {
  logger_ = std::shared_ptr<LoggerImpl>(new LoggerImpl(core::getClassName<LoggerConfiguration>(), get_logger(nullptr, root_namespace_, core::getClassName<LoggerConfiguration>(), formatter_)));
  loggers.push_back(logger_);
}

void LoggerConfiguration::initialize(const std::shared_ptr<LoggerProperties> &logger_properties) {
  std::lock_guard<std::mutex> lock(mutex);
  root_namespace_ = initialize_namespaces(logger_properties);
  std::string spdlog_pattern;
  if (!logger_properties->get("spdlog.pattern", spdlog_pattern)) {
    spdlog_pattern = spdlog_default_pattern;
  }
  formatter_ = std::make_shared<spdlog::pattern_formatter>(spdlog_pattern);
  std::map<std::string, std::shared_ptr<spdlog::logger>> spdloggers;
  for (auto const & logger_impl : loggers) {
    std::shared_ptr<spdlog::logger> spdlogger;
    auto it = spdloggers.find(logger_impl->name);
    if (it == spdloggers.end()) {
      spdlogger = get_logger(logger_, root_namespace_, logger_impl->name, formatter_, true);
      spdloggers[logger_impl->name] = spdlogger;
    } else {
      spdlogger = it->second;
    }
    logger_impl->set_delegate(spdlogger);
  }
  logger_->log_debug("Set following pattern on loggers: %s", spdlog_pattern);
}

std::shared_ptr<Logger> LoggerConfiguration::getLogger(const std::string &name) {
  std::lock_guard<std::mutex> lock(mutex);
  std::shared_ptr<LoggerImpl> result = std::make_shared<LoggerImpl>(name, get_logger(logger_, root_namespace_, name, formatter_));
  loggers.push_back(result);
  return result;
}

std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration::initialize_namespaces(const std::shared_ptr<LoggerProperties> &logger_properties) {
  std::map<std::string, std::shared_ptr<spdlog::sinks::sink>> sink_map = logger_properties->initial_sinks();

  std::string appender_type = "appender";
  for (auto const & appender_key : logger_properties->get_keys_of_type(appender_type)) {
    std::string appender_name = appender_key.substr(appender_type.length() + 1);
    std::string appender_type;
    if (!logger_properties->get(appender_key, appender_type)) {
      appender_type = "stderr";
    }
    std::transform(appender_type.begin(), appender_type.end(), appender_type.begin(), ::tolower);

    if ("nullappender" == appender_type || "null appender" == appender_type || "null" == appender_type) {
      sink_map[appender_name] = std::make_shared<spdlog::sinks::null_sink_st>();
    } else if ("rollingappender" == appender_type || "rolling appender" == appender_type || "rolling" == appender_type) {
      std::string file_name = "";
      if (!logger_properties->get(appender_key + ".file_name", file_name)) {
        file_name = "minifi-app.log";
      }
      std::string directory = "";
      directory = logger_properties->getHome();
      if (!directory.empty()) {
        // Create the log directory if needed
        directory += "/logs";
        struct stat logDirStat;
        if (stat(directory.c_str(), &logDirStat) != 0 || !S_ISDIR(logDirStat.st_mode)) {
          if (mkdir(directory.c_str(), 0777) == -1) {
            exit(1);
          }
        }
        file_name = directory + "/" + file_name;
      }

      int max_files = 3;
      std::string max_files_str = "";
      if (logger_properties->get(appender_key + ".max_files", max_files_str)) {
        try {
          max_files = std::stoi(max_files_str);
        } catch (const std::invalid_argument &ia) {
        } catch (const std::out_of_range &oor) {
        }
      }

      int max_file_size = 5 * 1024 * 1024;
      std::string max_file_size_str = "";
      if (logger_properties->get(appender_key + ".max_file_size", max_file_size_str)) {
        try {
          max_file_size = std::stoi(max_file_size_str);
        } catch (const std::invalid_argument &ia) {
        } catch (const std::out_of_range &oor) {
        }
      }
      sink_map[appender_name] = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_name, max_file_size, max_files);
    } else if ("stdout" == appender_type) {
      sink_map[appender_name] = spdlog::sinks::stdout_sink_mt::instance();
    } else {
      sink_map[appender_name] = spdlog::sinks::stderr_sink_mt::instance();
    }
  }

  std::shared_ptr<internal::LoggerNamespace> root_namespace = std::make_shared<internal::LoggerNamespace>();
  std::string logger_type = "logger";
  for (auto const & logger_key : logger_properties->get_keys_of_type(logger_type)) {
    std::string logger_def;
    if (!logger_properties->get(logger_key, logger_def)) {
      continue;
    }
    bool first = true;
    spdlog::level::level_enum level = spdlog::level::info;
    std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks;
    for (auto const & segment : utils::StringUtils::split(logger_def, ",")) {
      std::string level_name = utils::StringUtils::trim(segment);
      if (first) {
        first = false;
        std::transform(level_name.begin(), level_name.end(), level_name.begin(), ::tolower);
        if ("trace" == level_name) {
          level = spdlog::level::trace;
        } else if ("debug" == level_name) {
          level = spdlog::level::debug;
        } else if ("warn" == level_name) {
          level = spdlog::level::warn;
        } else if ("critical" == level_name) {
          level = spdlog::level::critical;
        } else if ("error" == level_name) {
          level = spdlog::level::err;
        } else if ("off" == level_name) {
          level = spdlog::level::off;
        }
      } else {
        sinks.push_back(sink_map[level_name]);
      }
    }
    std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace;
    if (logger_key != "logger.root") {
      for (auto const & name : utils::StringUtils::split(logger_key.substr(logger_type.length() + 1, logger_key.length() - logger_type.length()), "::")) {
        auto child_pair = current_namespace->children.find(name);
        std::shared_ptr<internal::LoggerNamespace> child;
        if (child_pair == current_namespace->children.end()) {
          child = std::make_shared<internal::LoggerNamespace>();
          current_namespace->children[name] = child;
        } else {
          child = child_pair->second;
        }
        current_namespace = child;
      }
    }
    current_namespace->level = level;
    current_namespace->has_level = true;
    current_namespace->sinks = sinks;
  }
  return root_namespace;
}

std::shared_ptr<spdlog::logger> LoggerConfiguration::get_logger(std::shared_ptr<Logger> logger, const std::shared_ptr<internal::LoggerNamespace> &root_namespace, const std::string &name,
                                                                std::shared_ptr<spdlog::formatter> formatter, bool remove_if_present) {
  std::shared_ptr<spdlog::logger> spdlogger = spdlog::get(name);
  if (spdlogger) {
    if (remove_if_present) {
      spdlog::drop(name);
    } else {
      return spdlogger;
    }
  }
  std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace;
  std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks = root_namespace->sinks;
  spdlog::level::level_enum level = root_namespace->level;
  std::string current_namespace_str = "";
  std::string sink_namespace_str = "root";
  std::string level_namespace_str = "root";
  for (auto const & name_segment : utils::StringUtils::split(name, "::")) {
    current_namespace_str += name_segment;
    auto child_pair = current_namespace->children.find(name_segment);
    if (child_pair == current_namespace->children.end()) {
      break;
    }
    current_namespace = child_pair->second;
    if (current_namespace->sinks.size() > 0) {
      sinks = current_namespace->sinks;
      sink_namespace_str = current_namespace_str;
    }
    if (current_namespace->has_level) {
      level = current_namespace->level;
      level_namespace_str = current_namespace_str;
    }
    current_namespace_str += "::";
  }
  if (logger != nullptr) {
    logger->log_debug("%s logger got sinks from namespace %s and level %s from namespace %s", name, sink_namespace_str, spdlog::level::level_names[level], level_namespace_str);
  }
  spdlogger = std::make_shared<spdlog::logger>(name, begin(sinks), end(sinks));
  spdlogger->set_level(level);
  spdlogger->set_formatter(formatter);
  spdlogger->flush_on(std::max(spdlog::level::info, current_namespace->level));
  try {
    spdlog::register_logger(spdlogger);
  } catch (const spdlog::spdlog_ex &ex) {
    // Ignore as someone else beat us to registration, we should get the one they made below
  }
  return spdlog::get(name);
}

std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration::create_default_root() {
  std::shared_ptr<internal::LoggerNamespace> result = std::make_shared<internal::LoggerNamespace>();
  result->sinks = std::vector<std::shared_ptr<spdlog::sinks::sink>>();
  result->sinks.push_back(spdlog::sinks::stderr_sink_mt::instance());
  result->level = spdlog::level::info;
  return result;
}

} /* namespace logging */
} /* namespace core */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
<|endoftext|>


<commit_before>// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_
#define ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_

#include <type_traits>

// HC API
#include <hcc/hc.hpp>

#include "../detail/config.hpp"
#include "../detail/various.hpp"
#include "../detail/radix_sort.hpp"

#include "../intrinsics.hpp"
#include "../functional.hpp"

#include "block_scan.hpp"

BEGIN_ROCPRIM_NAMESPACE

namespace detail
{

template<class T, unsigned int Size>
struct buckets
{
    static constexpr unsigned int size = Size;
    T xs[Size];

    buckets operator+(const buckets& b) const [[hc]]
    {
        buckets c;
        for(unsigned int r = 0; r < Size; r++)
        {
            c[r] = xs[r] + b[r];
        }
        return c;
    }

    T& operator[](unsigned int idx) [[hc]]
    {
        return xs[idx];
    }

    T operator[](unsigned int idx) const [[hc]]
    {
        return xs[idx];
    }
};

template<class T>
void warp_bit_plus_exlusive_scan(const T input, T& output) [[hc]]
{
    const unsigned int lane_id = ::rocprim::lane_id();
    const unsigned long long prev_lanes_mask = (1ull << lane_id) - 1;
    output = hc::__popcount_u32_b64(hc::__ballot(input) & prev_lanes_mask);
}

template<class T, unsigned int Size>
void warp_bit_plus_exlusive_scan(const buckets<T, Size>& input, buckets<T, Size>& output) [[hc]]
{
    for(unsigned int r = 0; r < Size; r++)
    {
        warp_bit_plus_exlusive_scan(input[r], output[r]);
    }
}

template<
    class T,
    unsigned int BlockSize,
    unsigned int ItemsPerThread
>
struct block_bit_plus_scan
{
    // Select warp size
    static constexpr unsigned int warp_size =
        detail::get_min_warp_size(BlockSize, ::rocprim::warp_size());
    // Number of warps in block
    static constexpr unsigned int warps_no = (BlockSize + warp_size - 1) / warp_size;

    static constexpr unsigned int prefix_scan_warp_size =
        detail::next_power_of_two(warps_no * ItemsPerThread);
    // TODO use block_scan for such cases?
    static_assert(prefix_scan_warp_size <= ::rocprim::warp_size(),
        "ItemsPerThread is too large for the current BlockSize");

    using prefix_scan = ::rocprim::warp_scan<T, prefix_scan_warp_size>;

    struct storage_type
    {
        T warp_scan_results[warps_no * ItemsPerThread];
    };

    void exclusive_scan(const T (& input)[ItemsPerThread],
                        T (& output)[ItemsPerThread],
                        T& reduction) [[hc]]
    {
        tile_static storage_type storage;
        return this->exclusive_scan(input, output, reduction, storage);
    }

    void exclusive_scan(const T (& input)[ItemsPerThread],
                        T (& output)[ItemsPerThread],
                        T& reduction,
                        storage_type& storage) [[hc]]
    {
        const unsigned int lane_id = ::rocprim::lane_id();
        const unsigned int warp_id = ::rocprim::warp_id();

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            // Perform exclusive warp scan of bit values
            warp_bit_plus_exlusive_scan(input[i], output[i]);

            // Save the warp reduction result, that is the scan result
            // for last element in each warp including its value
            if(lane_id == warp_size - 1 || (warp_id == warps_no - 1 && lane_id == BlockSize % warp_size - 1))
            {
                const unsigned int warp_prefix_id = warp_id * ItemsPerThread + i;
                storage.warp_scan_results[warp_prefix_id] = output[i] + input[i];
            }
        }
        ::rocprim::syncthreads();

        // Scan the warp reduction results
        if(warp_id == 0)
        {
            const unsigned int warp_prefix_id = lane_id;
            // TODO what about small BlockSize and large ItemsPerThread? Not enough active lanes
            // to scan all values
            if(warp_prefix_id < warps_no * ItemsPerThread)
            {
                auto warp_prefix = storage.warp_scan_results[warp_prefix_id];
                prefix_scan().inclusive_scan(warp_prefix, warp_prefix, ::rocprim::plus<T>());
                storage.warp_scan_results[warp_prefix_id] = warp_prefix;
            }
        }
        ::rocprim::syncthreads();

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            // Calculate the final scan result for every thread
            const unsigned int warp_prefix_id = warp_id * ItemsPerThread + i;
            if(warp_prefix_id != 0)
            {
                auto warp_prefix = storage.warp_scan_results[warp_prefix_id - 1];
                output[i] = warp_prefix + output[i];
            }
        }

        // Get the final inclusive reduction result
        reduction = storage.warp_scan_results[warps_no * ItemsPerThread - 1];
    }
};

} // end namespace detail

template<
    class Key,
    unsigned int BlockSize,
    unsigned int ItemsPerThread = 1,
    class Value = detail::empty_type,
    unsigned int RadixBits = 2
>
class block_radix_sort
{
public:
    using key_codec = ::rocprim::detail::radix_key_codec<Key>;
    using bit_key_type = typename key_codec::bit_key_type;

    // Select warp size
    static constexpr unsigned int warp_size =
        detail::get_min_warp_size(BlockSize, ::rocprim::warp_size());
    // Number of warps in block
    static constexpr unsigned int warps_no = (BlockSize + warp_size - 1) / warp_size;

    struct storage_type
    {
        bit_key_type bit_keys[BlockSize * ItemsPerThread];
    };

    void sort(Key (& keys)[ItemsPerThread],
              unsigned int begin_bit = 0,
              unsigned int end_bit = 8 * sizeof(Key)) [[hc]]
    {
        tile_static storage_type storage;
        sort(keys, storage, begin_bit, end_bit);
    }

    void sort(Key (& keys)[ItemsPerThread],
              storage_type& storage,
              unsigned int begin_bit = 0,
              unsigned int end_bit = 8 * sizeof(Key)) [[hc]]
    {
        const unsigned int thread_id = ::rocprim::flat_block_thread_id();
        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            storage.bit_keys[thread_id * ItemsPerThread + i] = key_codec::encode(keys[i]);
        }
        ::rocprim::syncthreads();

        constexpr unsigned int radix_size = 1 << RadixBits;
        using buckets = detail::buckets<unsigned int, radix_size>;

        detail::block_bit_plus_scan<buckets, BlockSize, ItemsPerThread> scan;

        const unsigned int lane_id = ::rocprim::lane_id();
        const unsigned int warp_id = ::rocprim::warp_id();
        const unsigned int current_warp_size = (warp_id == warps_no - 1)
            ? (BlockSize % warp_size > 0 ? BlockSize % warp_size : warp_size)
            : warp_size;

        #pragma unroll 1
        for(unsigned int bit = begin_bit; bit < end_bit; bit += RadixBits)
        {
            bit_key_type bit_keys[ItemsPerThread];
            buckets banks[ItemsPerThread];
            buckets positions[ItemsPerThread];
            buckets counts;

            const unsigned int radix_mask = ::rocprim::min(radix_size, 1u << (end_bit - bit)) - 1;
            for(unsigned int i = 0; i < ItemsPerThread; i++)
            {
                const bit_key_type bit_key = storage.bit_keys[warp_id * warp_size * ItemsPerThread + i * current_warp_size + lane_id];
                bit_keys[i] = bit_key;
                const unsigned int radix = (bit_key >> bit) & radix_mask;
                for(unsigned int r = 0; r < radix_size; r++)
                {
                    banks[i][r] = radix == r;
                }
            }
            scan.exclusive_scan(banks, positions, counts);

            // Prefix sum of counts to compute starting positions of keys of each radix value
            unsigned int prefix = 0;
            for(unsigned int r = 0; r < radix_size; r++)
            {
                const unsigned int c = counts[r];
                counts[r] = prefix;
                prefix += c;
            }
            // Scatter keys to computed positions considering starting positions of their
            // radix values
            for(unsigned int i = 0; i < ItemsPerThread; i++)
            {
                const bit_key_type bit_key = bit_keys[i];
                const unsigned int radix = (bit_key >> bit) & radix_mask;
                unsigned int position = 0;
                for(unsigned int r = 0; r < radix_size; r++)
                {
                    position = radix == r ? (counts[r] + positions[i][r]) : position;
                }
                storage.bit_keys[position] = bit_key;
            }
            ::rocprim::syncthreads();
        }

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            keys[i] = key_codec::decode(storage.bit_keys[thread_id * ItemsPerThread + i]);
        }
    }

private:

};

END_ROCPRIM_NAMESPACE

#endif // ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_
<commit_msg>Store shared memory for inner scans inside block_radix_sort's storage<commit_after>// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_
#define ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_

#include <type_traits>

// HC API
#include <hcc/hc.hpp>

#include "../detail/config.hpp"
#include "../detail/various.hpp"
#include "../detail/radix_sort.hpp"

#include "../intrinsics.hpp"
#include "../functional.hpp"

#include "block_scan.hpp"

BEGIN_ROCPRIM_NAMESPACE

namespace detail
{

template<class T, unsigned int Size>
struct buckets
{
    static constexpr unsigned int size = Size;
    T xs[Size];

    buckets operator+(const buckets& b) const [[hc]]
    {
        buckets c;
        for(unsigned int r = 0; r < Size; r++)
        {
            c[r] = xs[r] + b[r];
        }
        return c;
    }

    T& operator[](unsigned int idx) [[hc]]
    {
        return xs[idx];
    }

    T operator[](unsigned int idx) const [[hc]]
    {
        return xs[idx];
    }
};

template<class T>
void warp_bit_plus_exlusive_scan(const T input, T& output) [[hc]]
{
    const unsigned int lane_id = ::rocprim::lane_id();
    const unsigned long long prev_lanes_mask = (1ull << lane_id) - 1;
    output = hc::__popcount_u32_b64(hc::__ballot(input) & prev_lanes_mask);
}

template<class T, unsigned int Size>
void warp_bit_plus_exlusive_scan(const buckets<T, Size>& input, buckets<T, Size>& output) [[hc]]
{
    for(unsigned int r = 0; r < Size; r++)
    {
        warp_bit_plus_exlusive_scan(input[r], output[r]);
    }
}

template<
    class T,
    unsigned int BlockSize,
    unsigned int ItemsPerThread
>
class block_bit_plus_scan
{
    // Select warp size
    static constexpr unsigned int warp_size =
        detail::get_min_warp_size(BlockSize, ::rocprim::warp_size());
    // Number of warps in block
    static constexpr unsigned int warps_no = (BlockSize + warp_size - 1) / warp_size;

    static constexpr unsigned int prefix_scan_size =
        detail::next_power_of_two(warps_no * ItemsPerThread);
    // TODO use block_scan for such cases?
    static_assert(prefix_scan_size <= ::rocprim::warp_size(),
        "ItemsPerThread is too large for the current BlockSize");

    using prefix_scan = ::rocprim::warp_scan<T, prefix_scan_size>;

public:

    struct storage_type
    {
        T scan_results[warps_no * ItemsPerThread];
        typename prefix_scan::storage_type prefix_scan;
    };

    void exclusive_scan(const T (& input)[ItemsPerThread],
                        T (& output)[ItemsPerThread],
                        T& reduction) [[hc]]
    {
        tile_static storage_type storage;
        return exclusive_scan(input, output, reduction, storage);
    }

    void exclusive_scan(const T (& input)[ItemsPerThread],
                        T (& output)[ItemsPerThread],
                        T& reduction,
                        storage_type& storage) [[hc]]
    {
        const unsigned int lane_id = ::rocprim::lane_id();
        const unsigned int warp_id = ::rocprim::warp_id();
        const unsigned int current_warp_size = (warp_id == warps_no - 1)
            ? (BlockSize % warp_size > 0 ? BlockSize % warp_size : warp_size)
            : warp_size;

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            // Perform exclusive warp scan of bit values
            warp_bit_plus_exlusive_scan(input[i], output[i]);

            // Save the warp reduction result, that is the scan result
            // for last element in each warp including its value
            if(lane_id == current_warp_size - 1)
            {
                const unsigned int prefix_id = warp_id * ItemsPerThread + i;
                storage.scan_results[prefix_id] = output[i] + input[i];
            }
        }
        ::rocprim::syncthreads();

        // Scan the warp reduction results
        if(warp_id == 0)
        {
            const unsigned int prefix_id = lane_id;
            // TODO what about small BlockSize and large ItemsPerThread? Not enough active lanes
            // to scan all values
            if(prefix_id < warps_no * ItemsPerThread)
            {
                auto prefix = storage.scan_results[prefix_id];
                ::rocprim::plus<T> plus;
                prefix_scan().inclusive_scan(prefix, prefix, storage.prefix_scan, plus);
                storage.scan_results[prefix_id] = prefix;
            }
        }
        ::rocprim::syncthreads();

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            // Calculate the final scan result for every thread
            const unsigned int prefix_id = warp_id * ItemsPerThread + i;
            if(prefix_id != 0)
            {
                auto prefix = storage.scan_results[prefix_id - 1];
                output[i] = prefix + output[i];
            }
        }

        // Get the final inclusive reduction result
        reduction = storage.scan_results[warps_no * ItemsPerThread - 1];
    }
};

} // end namespace detail

template<
    class Key,
    unsigned int BlockSize,
    unsigned int ItemsPerThread = 1,
    class Value = detail::empty_type,
    unsigned int RadixBits = 2
>
class block_radix_sort
{
    static constexpr unsigned int radix_size = 1 << RadixBits;

    using key_codec = ::rocprim::detail::radix_key_codec<Key>;
    using bit_key_type = typename key_codec::bit_key_type;

    using buckets = detail::buckets<unsigned int, radix_size>;
    using block_bit_plus_scan = detail::block_bit_plus_scan<buckets, BlockSize, ItemsPerThread>;

    // Select warp size
    static constexpr unsigned int warp_size =
        detail::get_min_warp_size(BlockSize, ::rocprim::warp_size());
    // Number of warps in block
    static constexpr unsigned int warps_no = (BlockSize + warp_size - 1) / warp_size;

public:

    struct storage_type
    {
        bit_key_type bit_keys[BlockSize * ItemsPerThread];
        typename block_bit_plus_scan::storage_type block_bit_plus_scan;
    };

    void sort(Key (& keys)[ItemsPerThread],
              unsigned int begin_bit = 0,
              unsigned int end_bit = 8 * sizeof(Key)) [[hc]]
    {
        tile_static storage_type storage;
        sort(keys, storage, begin_bit, end_bit);
    }

    void sort(Key (& keys)[ItemsPerThread],
              storage_type& storage,
              unsigned int begin_bit = 0,
              unsigned int end_bit = 8 * sizeof(Key)) [[hc]]
    {
        const unsigned int thread_id = ::rocprim::flat_block_thread_id();
        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            storage.bit_keys[thread_id * ItemsPerThread + i] = key_codec::encode(keys[i]);
        }
        ::rocprim::syncthreads();

        block_bit_plus_scan scan;

        const unsigned int lane_id = ::rocprim::lane_id();
        const unsigned int warp_id = ::rocprim::warp_id();
        const unsigned int current_warp_size = (warp_id == warps_no - 1)
            ? (BlockSize % warp_size > 0 ? BlockSize % warp_size : warp_size)
            : warp_size;

        for(unsigned int bit = begin_bit; bit < end_bit; bit += RadixBits)
        {
            bit_key_type bit_keys[ItemsPerThread];
            buckets banks[ItemsPerThread];
            buckets positions[ItemsPerThread];
            buckets counts;

            // Handle cases when (end_bit - bit) is not divisible by RadixBits, i.e. the last
            // iteration has a shorter mask.
            const unsigned int radix_mask = (1u << ::rocprim::min(RadixBits, end_bit - bit)) - 1;

            for(unsigned int i = 0; i < ItemsPerThread; i++)
            {
                const bit_key_type bit_key = storage.bit_keys[
                    warp_id * warp_size * ItemsPerThread + i * current_warp_size + lane_id
                ];
                bit_keys[i] = bit_key;
                const unsigned int radix = (bit_key >> bit) & radix_mask;
                for(unsigned int r = 0; r < radix_size; r++)
                {
                    banks[i][r] = radix == r;
                }
            }
            scan.exclusive_scan(banks, positions, counts, storage.block_bit_plus_scan);

            // Prefix sum of counts to compute starting positions of keys of each radix value
            unsigned int prefix = 0;
            for(unsigned int r = 0; r < radix_size; r++)
            {
                const unsigned int c = counts[r];
                counts[r] = prefix;
                prefix += c;
            }
            // Scatter keys to computed positions considering starting positions of their
            // radix values
            for(unsigned int i = 0; i < ItemsPerThread; i++)
            {
                const bit_key_type bit_key = bit_keys[i];
                const unsigned int radix = (bit_key >> bit) & radix_mask;
                unsigned int position = 0;
                for(unsigned int r = 0; r < radix_size; r++)
                {
                    position = radix == r ? (counts[r] + positions[i][r]) : position;
                }
                storage.bit_keys[position] = bit_key;
            }
            ::rocprim::syncthreads();
        }

        for(unsigned int i = 0; i < ItemsPerThread; i++)
        {
            keys[i] = key_codec::decode(storage.bit_keys[thread_id * ItemsPerThread + i]);
        }
    }
};

END_ROCPRIM_NAMESPACE

#endif // ROCPRIM_BLOCK_BLOCK_RADIX_SORT_HPP_
<|endoftext|>


<commit_before>#include <Scenes/IntegrationTestScene.hpp>

namespace asc {
	IntegrationTestScene::IntegrationTestScene(void)
		: Scene("IntegrationTestScene") {

		m_AddedCallbackId = m_EntityManager.OnEntityAdded.registerCallback(std::bind(
			&EntityRepresentationManager::handleRegisterEntity,
			&m_EntityRepresentationManager,
			std::placeholders::_1));
		m_RemovedCallbackId = m_EntityManager.OnEntityRemoved.registerCallback(std::bind(
			&EntityRepresentationManager::handleUnregisterEntity,
			&m_EntityRepresentationManager,
			std::placeholders::_1));
	}
	IntegrationTestScene::~IntegrationTestScene(void) {
		m_EntityManager.OnEntityAdded.unregisterCallback(m_RemovedCallbackId);
		m_EntityManager.OnEntityRemoved.unregisterCallback(m_RemovedCallbackId);
	}

	void IntegrationTestScene::update(float _delta) {
		m_EntityManager.updateEntities(_delta);
		m_EntityRepresentationManager.update(_delta);
	}

	bool IntegrationTestScene::handleEvent(const sf::Event& _event) {
		if (_event.type == sf::Event::KeyPressed) {
			if (_event.key.code == sf::Keyboard::Left) {
				Application::getCamera().move(sf::Vector2f(-20.0f, +0.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Right) {
				Application::getCamera().move(sf::Vector2f(+20.0f, +0.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Up) {
				Application::getCamera().move(sf::Vector2f(+0.0f, +20.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Down) {
				Application::getCamera().move(sf::Vector2f(+0.0f, -20.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::F1) {
				Application::getCamera().setPosition(sf::Vector2f());
				Application::getCamera().setZoom(1.0f);
				return true;
			}
		}

		if (_event.type == sf::Event::MouseWheelMoved) {
			if (_event.mouseWheel.delta > 0) {
				Application::getCamera().zoom(pow(1.1f, fabsf(static_cast<float>(_event.mouseWheel.delta))));
				return true;
			}
			if (_event.mouseWheel.delta < 0) {
				Application::getCamera().zoom(pow(1.0f / 1.1f, fabsf(static_cast<float>(_event.mouseWheel.delta))));
				return true;
			}
		}

		return false;
	}

	void IntegrationTestScene::draw(sf::RenderTarget& _target, sf::RenderStates _states) const {
		sf::CircleShape c(32.0f);
		c.setOrigin(32.0f, 32.0f);
		_target.draw(c, _states);

		m_EntityRepresentationManager.draw(_target, _states);
	}
}<commit_msg>add math header<commit_after>#include <Scenes/IntegrationTestScene.hpp>

#include <cmath>

namespace asc {
	IntegrationTestScene::IntegrationTestScene(void)
		: Scene("IntegrationTestScene") {

		m_AddedCallbackId = m_EntityManager.OnEntityAdded.registerCallback(std::bind(
			&EntityRepresentationManager::handleRegisterEntity,
			&m_EntityRepresentationManager,
			std::placeholders::_1));
		m_RemovedCallbackId = m_EntityManager.OnEntityRemoved.registerCallback(std::bind(
			&EntityRepresentationManager::handleUnregisterEntity,
			&m_EntityRepresentationManager,
			std::placeholders::_1));
	}
	IntegrationTestScene::~IntegrationTestScene(void) {
		m_EntityManager.OnEntityAdded.unregisterCallback(m_RemovedCallbackId);
		m_EntityManager.OnEntityRemoved.unregisterCallback(m_RemovedCallbackId);
	}

	void IntegrationTestScene::update(float _delta) {
		m_EntityManager.updateEntities(_delta);
		m_EntityRepresentationManager.update(_delta);
	}

	bool IntegrationTestScene::handleEvent(const sf::Event& _event) {
		if (_event.type == sf::Event::KeyPressed) {
			if (_event.key.code == sf::Keyboard::Left) {
				Application::getCamera().move(sf::Vector2f(-20.0f, +0.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Right) {
				Application::getCamera().move(sf::Vector2f(+20.0f, +0.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Up) {
				Application::getCamera().move(sf::Vector2f(+0.0f, +20.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::Down) {
				Application::getCamera().move(sf::Vector2f(+0.0f, -20.0f));
				return true;
			}
			if (_event.key.code == sf::Keyboard::F1) {
				Application::getCamera().setPosition(sf::Vector2f());
				Application::getCamera().setZoom(1.0f);
				return true;
			}
		}

		if (_event.type == sf::Event::MouseWheelMoved) {
			if (_event.mouseWheel.delta > 0) {
				Application::getCamera().zoom(pow(1.1f, fabsf(static_cast<float>(_event.mouseWheel.delta))));
				return true;
			}
			if (_event.mouseWheel.delta < 0) {
				Application::getCamera().zoom(pow(1.0f / 1.1f, fabsf(static_cast<float>(_event.mouseWheel.delta))));
				return true;
			}
		}

		return false;
	}

	void IntegrationTestScene::draw(sf::RenderTarget& _target, sf::RenderStates _states) const {
		sf::CircleShape c(32.0f);
		c.setOrigin(32.0f, 32.0f);
		_target.draw(c, _states);

		m_EntityRepresentationManager.draw(_target, _states);
	}
}<|endoftext|>