//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of Pane Splitter classes
//----------------------------------------------------------------------------
#include <owl/pch.h>
 
#include <owl/contain.h>
#include <owl/layoutwi.h>
#include <owl/panespli.h>
#include <owl/uihelper.h>
#include <owl/dc.h>
#include <owl/uimetric.h>
#include <owl/template.h>
 
#include <math.h>
 
namespace owl {
 
OWL_DIAGINFO;
 
 
//
// Defines to make typesafe downcasting simpler.
//
#define SPLITTER(x) TYPESAFE_DOWNCAST(x,TSplitter)
#define LAYOUTWINDOW(x) TYPESAFE_DOWNCAST(x,TLayoutWindow)
//#define USE_CUSTOM_CURSORS
 
 
#if !defined(BI_COMP_GNUC)
#  pragma warn -inl
#endif
void TSplitterIndicatorList::Flush(bool del)
{
  if(del){
    for(TSplitterIndicatorListIterator iter(*this); iter; iter++)
      delete *iter;
  }
  TBaseList<TSplitterIndicator*>::Flush();
}
#if !defined(BI_COMP_GNUC)
#  pragma warn .inl
#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// TSplitter class.
//
 
DEFINE_RESPONSE_TABLE1(TSplitter, TLayoutWindow)
  EV_WM_LBUTTONDOWN,
  EV_WM_MOUSEMOVE,
  EV_WM_LBUTTONUP,
  EV_WM_SETCURSOR,
  EV_WM_SIZE,
END_RESPONSE_TABLE;
 
//
// Constructor for abstract base class - don't set a border.
//
TSplitter::TSplitter(TWindow* parent, TPaneSplitter* ps, float percent)
:
  TLayoutWindow(parent, 0, 0),
  PercentOf(percent),
  PaneSplitter(ps)
{
  Attr.Style &= ~WS_BORDER;
  Attr.Style |= WS_CLIPCHILDREN;
}
 
//
// Notify TPaneSplitter object that it should begin the splitter move process.
//
void
TSplitter::EvLButtonDown(uint /*modKeys*/, const TPoint& point)
{
  TPoint  p = point;
  MapWindowPoints(0, &p, 1);  // map to screen
  PaneSplitter->StartSplitterMove(this, p);
//  TLayoutWindow::EvLButtonDown(modKeys, point);
}
 
//
// Notify TPaneSplitter object that splitter has moved.
//
void
TSplitter::EvMouseMove(uint /*modKeys*/, const TPoint& point)
{
  TPoint  p = point;
  MapWindowPoints(0, &p, 1);  // map to screen
  PaneSplitter->MouseMoved(p);
//  TLayoutWindow::EvMouseMove(modKeys, point);
}
 
//
// Notify TPaneSplitter object that splitters have finished being moved.
//
void
TSplitter::EvLButtonUp(uint /*modKeys*/, const TPoint& point)
{
  TPoint  p = point;
  MapWindowPoints(0, &p, 1);  // map to screen
  PaneSplitter->EndSplitterMove(p);
//JRSTSplitter::EvLButtonUp(uint /*modKeys*/, TPoint& /*point*/)
//JRS{
//JRS  PaneSplitter->EndSplitterMove();
//  TLayoutWindow::EvLButtonUp(modKeys, point); // !CQ we may be deleted!
}
 
//
// Notify TPaneSplitter object that it should set the appropriate cursor.
//
bool
TSplitter::EvSetCursor(HWND hWndCursor, uint codeHitTest, TMsgId mouseMsg)
{
  TPoint p;
  if (hWndCursor == GetHandle() && codeHitTest == HTCLIENT) {
    GetCursorPos(p);
    PaneSplitter->SetSplitterMoveCursor(this, p);
  }
  else
    TLayoutWindow::EvSetCursor(hWndCursor, codeHitTest, mouseMsg);
  return true;
}
 
//
// Notify TPaneSplitter object that splitter needs to be repainted.
// This allows the user to draw the splitter.
//
void
TSplitter::Paint(TDC& dc, bool, TRect& rect)
{
  TLayoutWindow::Paint(dc, true, rect);
  PaneSplitter->DrawSplitter(dc, GetRect());
}
 
//
// Resize the splitter.  In certain situations the splitters that are
// nested in this splitter don't want to resize, in which case their
// sizes are adjusted (retained).
//
void
TSplitter::EvSize(uint sizeType, const TSize& size)
{
  if (sizeType != SIZE_MINIMIZED && PaneSplitter->PaneSplitterResizing)
    AdjForResize(size);
  TLayoutWindow::EvSize(sizeType, size);
}
 
//
// Common code for T*Splitter::Setup().  Sets pane's parent to this and
// sets their layout metrics.
//
void
TSplitter::SetupEpilog(TSplitter* s, TWindow* targetPane, TWindow* newPane,
                       TLayoutMetrics& lmOfTargetPane,
                       TLayoutMetrics& lmOfNewPane)
{
  targetPane->SetParent(s);
  newPane->SetParent(s);
  newPane->Create();
  SetChildLayoutMetrics(*targetPane, lmOfTargetPane);
  SetChildLayoutMetrics(*newPane, lmOfNewPane);
}
 
//
// Remove a pane from this splitter.
//
TLayoutWindow*
TSplitter::RemovePane(TWindow* pane, TShouldDelete::TDelete dt)
{
  // 'parentSplitter' represents the splitter 'this' splitter is contained in.
  // 'retval' indicates weather their is a parent splitter, if not then 'pane'
  // is only one.
  // 'otherPane' is other window contained in this splitter.
  //
  TSplitter*        parentSplitter = SPLITTER(GetParentO());
  TLayoutWindow*    retval = parentSplitter;
  TWindow*          otherPane = Pane1() == pane ? Pane2() : Pane1();
 
  TLayoutMetrics    lm1;
  TLayoutMetrics    lm2;
 
  pane->ShowWindow(SW_HIDE);
  if (parentSplitter) {
    TWindow*          p1 = parentSplitter->Pane1();
    TWindow*          p2 = parentSplitter->Pane2();
 
    parentSplitter->GetChildLayoutMetrics(*p1, lm1);
    parentSplitter->GetChildLayoutMetrics(*p2, lm2);
    pane->SetParent(0);               // remove pane.
    otherPane->SetParent(parentSplitter);   // move up one level.
 
    if (this == p1) {                 // if top or left pane is being removed.
      if (lm2.X.RelWin == this)       // adjust other panes layout metrics.
        lm2.X.RelWin = otherPane;
      else if (lm2.Y.RelWin == this)
        lm2.Y.RelWin = otherPane;
      parentSplitter->SetChildLayoutMetrics(*p2, lm2);
      parentSplitter->SetChildLayoutMetrics(*otherPane, lm1);
    }
    else {  // other pane's layout is same as one being removed.
            //
      parentSplitter->SetChildLayoutMetrics(*otherPane, lm2);
    }
  }
  else {                          // remove last pane.
    retval = LAYOUTWINDOW(GetParentO());
    TLayoutMetrics  lmOfOtherPane;
 
    PaneSplitter->GetDefLM(lmOfOtherPane);
    otherPane->SetParent(retval);
    pane->SetParent(0);
    retval->SetChildLayoutMetrics(*otherPane, lmOfOtherPane);
  }
  // Destroy pane.
  //
  RemoveChildLayoutMetrics(*pane);
  PaneSplitter->DestroyPane(pane, dt);
  return retval;
}
 
//----------------------------------------------------------------------------
// TVSplitter class.
//
 
//
// Constructor for a vertical splitter
//
TVSplitter::TVSplitter(TWindow* parent, TPaneSplitter* ps, float percent)
:
  TSplitter(parent, ps, percent)
{
  SetCaption(_T("VSplitter"));
}
 
//
// Return TRect for the visible area (in client coordinates) of splitter.
//
TRect
TVSplitter::GetRect()
{
  TRect     rect;
  TWindow*  p1 = Pane1();
 
  rect.left = p1->GetWindowAttr().X + p1->GetWindowAttr().W;
  rect.top = p1->GetWindowAttr().Y;
  rect.right = rect.left + PaneSplitter->GetSplitterWidth();
  rect.bottom = p1->GetWindowAttr().Y + p1->GetWindowAttr().H;
 
  return rect;
}
 
//
// Split given pane into 2 parts: itself and a new pane.
//
void
TVSplitter::Split(TWindow* targetPane, TWindow* newPane, TSplitDirection sd, float percent)
{
  // Panes contained in this splitter.
  //
  TWindow*        p1 = Pane1();
  TWindow*        p2 = Pane2();
  TLayoutMetrics  lm;
 
  GetChildLayoutMetrics(*p2, lm);
 
  // Create new splitter (will be a child of this splitter).
  //
  TSplitter* splitter;
  if (sd == psHorizontal)
    splitter = new THSplitter(this, PaneSplitter, percent);
  else
    splitter = new TVSplitter(this, PaneSplitter, percent);
 
  // Initialize new splitter by putting target and new pane into it.
  //
  splitter->Create();
  TLayoutMetrics lmOfSplitter = splitter->Setup(targetPane, newPane, percent);
 
  if (p1 == targetPane) {   // target pane == left pane.  adjust new splitter's
                            // width and other windows left edge to be
                            // adjacent to new splitter.
                            //
    lmOfSplitter.Width.Absolute(targetPane->GetWindowAttr().W);
 
    lm.X.RelWin = splitter;
    SetChildLayoutMetrics(*p2, lm);
  }
  else {                    // set new splitter to the right of left pane.
                            //
    lmOfSplitter.X.RightOf(p1, PaneSplitter->GetSplitterWidth());
  }
  SetChildLayoutMetrics(*splitter, lmOfSplitter);
}
 
//
// Setup layout metrics and children for new splitter. Return that
// layout metrics.
//
TLayoutMetrics
TVSplitter::Setup(TWindow* targetPane, TWindow* newPane, float percent)
{
  TLayoutMetrics  lmOfSplitter;
  TLayoutMetrics  lmOfPane1;
  TLayoutMetrics  lmOfPane2;
 
  PaneSplitter->GetDefLM(lmOfSplitter);
  lmOfPane1 = lmOfPane2 = lmOfSplitter;
 
  // Target pane's width is 1/2 of what it was.  New pane is to the right
  // of target pane.
  //
  lmOfPane1.Width.Absolute(static_cast<int>(targetPane->GetWindowAttr().W * percent));
  lmOfPane2.X.RightOf(targetPane, PaneSplitter->GetSplitterWidth());
  SetupEpilog(this, targetPane, newPane, lmOfPane1, lmOfPane2);
 
  return lmOfSplitter;
}
 
//
// Create splitter indicator for this splitter.
//
TSplitterIndicator*
TVSplitter::CreateSplitterIndicator()
{
  return new TVSplitterIndicator(this, GetScreenRect());
}
 
//
// Return left pane, or 0 if none exist.
//
TWindow*
TVSplitter::Pane1()
{
  TWindow*  p1 = GetFirstChild();
  if (p1) {
    TWindow*  p2 = p1->Next();
 
    return p1->GetWindowAttr().X <= p2->GetWindowAttr().X ? p1 : p2;
  }
  return 0;
}
 
//
// Return right pane, or 0 if none exist.
//
TWindow*
TVSplitter::Pane2()
{
  if (NumChildren() != 2)
    return 0;
 
  TWindow*  p1 = GetFirstChild();
  TWindow*  p2 = p1->Next();
 
  return p1->GetWindowAttr().X > p2->GetWindowAttr().X ? p1 : p2;
}
 
//
// Called as a result of parent being resized. Adjust width of pane 1 to make
// it appear this splitter didn't move.
//
void
TVSplitter::AdjForResize(const TSize& sz)
{
  TLayoutMetrics     lm;
  TWindow*           pane = Pane1();
 
  if (pane) {
    GetChildLayoutMetrics(*pane, lm);
    lm.Width.Absolute(static_cast<int>(GetPercent() * sz.cx)); //JJH added static cast
    SetChildLayoutMetrics(*pane, lm);
  }
}
 
//
// Move splitter given distance.  Accomplished by resizing pane 1.
//
void
TVSplitter::Move(int dist)
{
  TLayoutMetrics  lm;
  TWindow*        pane = Pane1();
 
  if (pane) {
    GetChildLayoutMetrics(*pane, lm);
    lm.Width.Absolute(lm.Width.Value + dist);
    SetChildLayoutMetrics(*pane, lm);
 
    // Calc new percent.
    //
    PercentOf = (float)lm.Width.Value / (float)Attr.W;
 
    // Update nested splitters to retain their positions.
    //
    TSplitter* splitter = SPLITTER(Pane2());
    if (splitter) {
      while (1) {
        if (splitter->SplitDirection() == SplitDirection()) {
          TLayoutMetrics lm;
          splitter->GetChildLayoutMetrics(*splitter->Pane1(), lm);
          lm.Width.Absolute(lm.Width.Value - dist);
          splitter->SetPercent((float)lm.Width.Value /
                               (float)(splitter->GetWindowAttr().W - dist));
          splitter->SetChildLayoutMetrics(*splitter->Pane1(), lm);
        }
        if ((splitter = SPLITTER(splitter->Pane1())) == 0)
          break;
      }
    }
  }
}
 
//
// Change the width of the splitter and then do a Layout() to see changes.
//
void
TVSplitter::AdjSplitterWidth(int w)
{
  TLayoutMetrics  lm;
 
  GetChildLayoutMetrics(*Pane2(), lm);
  lm.X.Value += w;
  SetChildLayoutMetrics(*Pane2(), lm);
  Layout();
}
 
//----------------------------------------------------------------------------
// THSplitter class.
//
 
//
// Constructor for a horizontal splitter
//
THSplitter::THSplitter(TWindow* parent, TPaneSplitter* ps, float percent)
:
  TSplitter(parent, ps, percent)
{
  SetCaption(_T("HSplitter"));
}
 
//
// Return TRect for the visible area (in client coordinates) of splitter.
//
TRect
THSplitter::GetRect()
{
  TRect     rect;
  TWindow*  p1 = Pane1();
 
  rect.left = p1->GetWindowAttr().X;
  rect.top = p1->GetWindowAttr().Y + p1->GetWindowAttr().H;
  rect.right = p1->GetWindowAttr().X + p1->GetWindowAttr().W;
  rect.bottom = rect.top + PaneSplitter->GetSplitterWidth();
 
  return rect;
}
 
//
// Split given pane into 2 parts: itself and a new pane.
//
void
THSplitter::Split(TWindow* targetPane, TWindow* newPane, TSplitDirection sd, float percent)
{
  // Panes contained in this splitter.
  //
  TWindow*       p1 = Pane1();
  TWindow*       p2 = Pane2();
  TLayoutMetrics lm;
 
  GetChildLayoutMetrics(*p2, lm);
 
  // Create new splitter (will be a child of this splitter).
  //
  TSplitter* splitter;
  if (sd == psHorizontal)
    splitter = new THSplitter(this, PaneSplitter, percent);
  else
    splitter = new TVSplitter(this, PaneSplitter, percent);
 
  // Initialize new splitter by putting target and new pane into it.
  //
  splitter->Create();
  TLayoutMetrics lmOfSplitter = splitter->Setup(targetPane, newPane, percent);
 
  if (p1 == targetPane) {   // target pane == top pane.  adjust new splitter's
                            // height and other windows top edge to be
                            // adjacent to new splitter.
                            //
    lmOfSplitter.Height.Absolute(targetPane->GetWindowAttr().H);
 
    lm.Y.RelWin = splitter;
    SetChildLayoutMetrics(*p2, lm);
  }
  else {                    // set new splitter to below top pane.
                            //
    lmOfSplitter.Y.Below(p1, PaneSplitter->GetSplitterWidth());
  }
  SetChildLayoutMetrics(*splitter, lmOfSplitter);
}
 
//
// Setup layout metrics and children for new splitter. Return that
// layout metrics.
//
TLayoutMetrics
THSplitter::Setup(TWindow* targetPane, TWindow* newPane, float percent)
{
  TLayoutMetrics  lmOfSplitter;
  TLayoutMetrics  lmOfPane1;
  TLayoutMetrics  lmOfPane2;
 
  PaneSplitter->GetDefLM(lmOfSplitter);
  lmOfPane1 = lmOfPane2 = lmOfSplitter;
 
  // Target pane's height is 1/2 of what it was.  New pane is below
  // target pane.
  //
  lmOfPane1.Height.Absolute(static_cast<int>(targetPane->GetWindowAttr().H * percent)); //JJH added static cast
  lmOfPane2.Y.Below(targetPane, PaneSplitter->GetSplitterWidth());
  SetupEpilog(this, targetPane, newPane, lmOfPane1, lmOfPane2);
 
  return lmOfSplitter;
}
 
//
// Create splitter indicator for this splitter.
//
TSplitterIndicator*
THSplitter::CreateSplitterIndicator()
{
  return new THSplitterIndicator(this, GetScreenRect());
}
 
//
// Return top pane, or 0 if none exist.
//
TWindow*
THSplitter::Pane1()
{
  TWindow* p1 = GetFirstChild();
 
  if (p1) {
    TWindow*  p2 = p1->Next();
 
    return p1->GetWindowAttr().Y <= p2->GetWindowAttr().Y ? p1 : p2;
  }
  return 0;
}
 
//
// Return bottom pane, or 0 if none exist.
//
TWindow*
THSplitter::Pane2()
{
  if (NumChildren() != 2)
    return 0;
 
  TWindow* p1 = GetFirstChild();
  TWindow* p2 = p1->Next();
 
  return p1->GetWindowAttr().Y > p2->GetWindowAttr().Y ? p1 : p2;
}
 
//
// Called as a result of parent being resized. Adjust height of pane 1 to make
// it appear this splitter didn't move.
//
void
THSplitter::AdjForResize(const TSize& sz)
{
  TLayoutMetrics lm;
  TWindow*       pane = Pane1();
 
  if (pane) {
    GetChildLayoutMetrics(*pane, lm);
    lm.Height.Absolute(static_cast<int>(GetPercent() * sz.cy)); //JJH added static cast
    SetChildLayoutMetrics(*pane, lm);
  }
}
 
//
// Move splitter given distance.  Accomplished by resizing pane 1.
//
void
THSplitter::Move(int dist)
{
  TLayoutMetrics  lm;
  TWindow*        pane = Pane1();
 
  if (pane) {
    GetChildLayoutMetrics(*pane, lm);
    lm.Height.Absolute(lm.Height.Value + dist);
    SetChildLayoutMetrics(*pane, lm);
 
    // Calc new percent.
    //
    PercentOf = (float)lm.Height.Value / (float)Attr.H;
 
    // Update nested splitters to retain there relative positions.
    //
    TSplitter* splitter = SPLITTER(Pane2());
    if (splitter) {
      while (1) {
        if (splitter->SplitDirection() == SplitDirection()) {
          TLayoutMetrics lm;
          splitter->GetChildLayoutMetrics(*splitter->Pane1(), lm);
          lm.Height.Absolute(lm.Height.Value - dist);
          splitter->SetPercent((float)lm.Height.Value /
                               (float)(splitter->GetWindowAttr().H - dist));
          splitter->SetChildLayoutMetrics(*splitter->Pane1(), lm);
        }
        if ((splitter = SPLITTER(splitter->Pane1())) == 0)
          break;
      }
    }
  }
}
 
//
// Change the width of the splitter and then do a Layout() to see changes.
//
void
THSplitter::AdjSplitterWidth(int w)
{
  TLayoutMetrics  lm;
 
  GetChildLayoutMetrics(*Pane2(), lm);
  lm.Y.Value += w;
  SetChildLayoutMetrics(*Pane2(), lm);
  Layout();
}
 
//----------------------------------------------------------------------------
// TSplitterIndicator class (Base class).
//
 
//
// Draw splitter indicator.  Use InvertRect() to create the effect.
//
void
TSplitterIndicator::Draw()
{
  if (!Showing) {
    Showing = true;
    auto dc = TWindowDC{Splitter->GetHandle()};
    const auto r = Splitter->MapScreenToClient(*this);
    dc.InvertRect(r);
  }
}
 
//----------------------------------------------------------------------------
// TVSplitterIndicator class.
//
 
//
// Connect either top or bottom side of indicator to either top or bottom side
// of given TRect. If top of given TRect is below indicator then connect to
// TRect's top, else if TRect is above indicator then connect to TRect's bottom.
// Assumes that given TRect represents a horizontal indicator.
//
void
TVSplitterIndicator::ConnectToRect(const TRect& rect)
{
  if (rect.top > bottom)
    bottom = rect.top;
  else if (rect.top < top)
    top = rect.bottom;
}
 
//
// Move splitter indicator (do not draw it though) given dist, which
// could be + (move right) or - (move left).  If the move would put the
// indicator out of the move area then move to edge of move area.
//
void
TVSplitterIndicator::Move(int dist)
{
  TRect moveArea = Splitter->GetMoveArea();
  TRect orig = Splitter->GetScreenRect();
  int   splitterWidth = right - left;
 
  left = orig.left + dist;
  right = left + splitterWidth;
  top = orig.top;
  bottom = orig.bottom;
 
  //
  // Don't allow the indicator to get closer to the edge of the moveArea
  // than the cushion.
  //
  if( moveArea.Width() > (int)Cushion )  {
    moveArea.left += Cushion;
    moveArea.right -= Cushion;
  }
  else {
    DistMoved = 0;
    return;
  }
 
 
  if (!moveArea.Contains(*this)) {
    // Indicator out of move area to put it adjacent to either top or bottom
    // of move area.
    //
    if (left < moveArea.left) {
      left = moveArea.left;
      right = left + splitterWidth;
    }
    else {
      right = moveArea.right;
      left = right - splitterWidth;
    }
  }
  else
    DistMoved = dist;
}
 
//
// Return distance moved (left or right) given starting and current point.
//
int
TVSplitterIndicator::CalcDistMoved(const TPoint& start, const TPoint& cur)
{
  return cur.x - start.x;
}
 
//
// A check to see if given point could be in indicator if indicator were
// streched.  This function is used when determining if multiple splitters
// intersect at a point (for dragging).
//
bool
TVSplitterIndicator::CouldContain(const TPoint& point)
{
  TRect r = *this;
  int   splitterWidth = right - left;
 
  r.top -= splitterWidth;
  r.bottom += splitterWidth;
  return r.Contains(point);
}
 
//
// Calculate the area in which the indicator moved.  Use original splitter
// position and current indicator position to calculate area. Used to
// determine which panes need to be removed.
//
TRect
TVSplitterIndicator::CalcAreaOfSplitterMove()
{
  TRect r1 = *this;
  TRect r2 = Splitter->GetScreenRect();
  TRect area = r2;
 
  if (r1.left < r2.left) {
    area.left = r1.left;
    area.right = r2.right;
  }
  else {
    area.left = r2.left;
    area.right = r1.right;
  }
  return area;
}
 
//----------------------------------------------------------------------------
// THSplitterIndicator class.
//
 
//
// Connect either left or right side of indicator to either left or right side
// of given TRect. If left side of given TRect is to the right of indicator
// then connect to TRect's left side, else if TRect is to the left of indicator
// then connect to TRect's right side. Assumes that given TRect represents a
// vertical indicator.
//
void
THSplitterIndicator::ConnectToRect(const TRect& rect)
{
  if (rect.left > right)
    right = rect.left;
  else if (rect.left < left)
    left = rect.right;
}
 
//
// Move splitter indicator (do not draw it though) given dist, which
// could be + (move down) or - (move up).  If the move would put the
// indicator out of the move area then move to edge of move area.
//
void
THSplitterIndicator::Move(int dist)
{
  TRect moveArea = Splitter->GetMoveArea();
  TRect orig = Splitter->GetScreenRect();
  int   splitterWidth = bottom - top;
 
  top = orig.top + dist;
  bottom = top + splitterWidth;
  left = orig.left;
  right = orig.right;
 
  //
  // Don't allow the indicator to get closer to the edge of the moveArea
  // than the cushion.
  //
  if( moveArea.Height() > (int)Cushion )  {
    moveArea.top += Cushion;
    moveArea.bottom -= Cushion;
  }
  else {
    DistMoved = 0;
    return;
  }
 
  if (!moveArea.Contains(*this)) {
    // Indicator out of move area to put it adjacent to either top or bottom
    // of move area.
    //
    if (top < moveArea.top) {
      top = moveArea.top;
      bottom = top + splitterWidth;
    }
    else {
      bottom = moveArea.bottom;
      top = bottom - splitterWidth;
    }
  }
  else
    DistMoved = dist;
}
 
//
// Return distance moved (up or down) given starting and current point.
//
int
THSplitterIndicator::CalcDistMoved(const TPoint& start, const TPoint& cur)
{
  return cur.y - start.y;
}
 
//
// A check to see if given point could be in indicator if indicator were
// streched.  This function is used when determining if multiple splitters
// intersect at a point (for dragging).
//
bool
THSplitterIndicator::CouldContain(const TPoint& point)
{
  TRect r = *this;
  int   splitterWidth = bottom - top;
 
  r.left -= splitterWidth;
  r.right += splitterWidth;
 
  return r.Contains(point);
}
 
//
// Calculate the area in which the indicator moved.  Use original splitter
// position and current indicator position to calculate area. Used to
// determine which panes need to be removed.
//
TRect
THSplitterIndicator::CalcAreaOfSplitterMove()
{
  TRect r1 = *this;
  TRect r2 = Splitter->GetScreenRect();
  TRect area = r2;
 
  if (r1.top < r2.top) {
    area.top = r1.top;
    area.bottom = r2.bottom;
  }
  else {
    area.top = r2.top;
    area.bottom = r1.bottom;
  }
  return area;
}
 
//----------------------------------------------------------------------------
// TSplitterIndicatorList class.
 
//
// Search for indicator that was created from given splitter.
//
TSplitterIndicator*
TSplitterIndicatorList::FindIndicatorWithSplitter(TSplitter* splitter)
{
  for(TSplitterIndicatorListIterator  iter(*this); iter; iter++){
    TSplitterIndicator* i = (TSplitterIndicator*)*iter;
    if (i->GetSplitter() == splitter)
      return i;
  }
  return 0;
}
 
//----------------------------------------------------------------------------
// TSplitterIndicatorMgr class.
//
 
//
// Save indicator list for later manipulation.  Record starting drag point.
// Draw splitter indicators.
//
void
TSplitterIndicatorMgr::StartMove(TSplitterIndicatorList& sil,
                                 const TPoint& point)
{
  SplitterIndicatorList = &sil;
  StartDragPoint = point;
  DrawIndicators();
}
 
//
// Clear indicators from screen.
//
void
TSplitterIndicatorMgr::EndMove()
{
  ClearIndicators();
}
 
//
// Move all indicators.  Distance moved is based on starting drag point and
// given point.
//
void
TSplitterIndicatorMgr::MoveIndicators(const TPoint& point)
{
  ClearIndicators();
 
  TSplitterIndicatorListIterator  iter(*SplitterIndicatorList);
 
  if (iter){
    TSplitterIndicator* main = (TSplitterIndicator*)*iter;
    while(iter) {
      TSplitterIndicator* si = (TSplitterIndicator*)*iter;
      int dist = si->CalcDistMoved(StartDragPoint, point);
      si->Move(dist);
      if (si != main)
        si->ConnectToRect(*main);
      iter++;
    }
  }
  DrawIndicators();
}
 
//
// Draw indicators on screen.
//
void
TSplitterIndicatorMgr::DrawIndicators()
{
  if( !SplitterIndicatorList )
    return;
  for(TSplitterIndicatorListIterator iter(*SplitterIndicatorList);iter;iter++)
    ((TSplitterIndicator*)*iter)->Draw();
}
 
//
// Clear all indicators from screen.
//
void
TSplitterIndicatorMgr::ClearIndicators()
{
  if( !SplitterIndicatorList )
    return;
  for(TSplitterIndicatorListIterator iter(*SplitterIndicatorList);iter;iter++)
    ((TSplitterIndicator*)*iter)->Clear();
}
 
//----------------------------------------------------------------------------
// TPaneSplitter class
//
 
DEFINE_RESPONSE_TABLE1(TPaneSplitter, TLayoutWindow)
  EV_WM_SIZE,
END_RESPONSE_TABLE;
 
 
//
/// Initializes data members.
//
TPaneSplitter::TPaneSplitter(TWindow*        parent,
                             LPCTSTR         title,
                             int             splitterWidth,
                             TModule*        module)
:
  TLayoutWindow(parent, title, module),
  Dragging(false),
  SplitterWidth(splitterWidth),
  SplitterCushion(0),
  PaneSplitterResizing(false),
  ShouldDelete(TShouldDelete::NoDelete)
{
  Attr.Style |= WS_CLIPCHILDREN;
  if (!SplitterWidth)
    SplitterWidth = TUIMetric::CxFixedFrame;
  SetCaption(_T("PaneSplitter"));
   SplitterIndicatorList = new TSplitterIndicatorList;
 
}
 
//
/// String-aware overload
//
TPaneSplitter::TPaneSplitter(
  TWindow* parent,
  const tstring& title,
  int splitterWidth,
  TModule* module
  )
  : TLayoutWindow(parent, title, module),
  Dragging(false),
  SplitterWidth(splitterWidth),
  SplitterCushion(0),
  PaneSplitterResizing(false),
  ShouldDelete(TShouldDelete::NoDelete)
{
  Attr.Style |= WS_CLIPCHILDREN;
  if (!SplitterWidth)
    SplitterWidth = TUIMetric::CxFixedFrame;
  SetCaption(_T("PaneSplitter"));
  SplitterIndicatorList = new TSplitterIndicatorList;
}
 
//
// Empty destructor
//
TPaneSplitter::~TPaneSplitter()
{
  SplitterIndicatorList->Flush(true);
  delete SplitterIndicatorList;
}
 
//
/// Loads cursors and sets TSplitter's pane splitter object.
//
void
TPaneSplitter::SetupWindow()
{
  TLayoutWindow::SetupWindow();
 
  // Load cursors.
  //
#if defined(USE_CUSTOM_CURSORS)
  ResizeCursorH = LoadCursor(IDC_RESIZE_H);
  ResizeCursorV = LoadCursor(IDC_RESIZE_V);
  ResizeCursorHV = LoadCursor(IDC_RESIZE_HV);
#else
  ResizeCursorH = ::LoadCursor(0, IDC_SIZENS);
  ResizeCursorV = ::LoadCursor(0, IDC_SIZEWE);
  ResizeCursorHV = ::LoadCursor(0, IDC_SIZEALL);
#endif
}
 
//
/// Removes all panes (and related splitters). Destroys cursors.
//
void
TPaneSplitter::CleanupWindow()
{
  RemoveAllPanes();
 
#if defined(USE_CUSTOM_CURSORS)
  ::DestroyCursor(ResizeCursorH);
  ::DestroyCursor(ResizeCursorV);
  ::DestroyCursor(ResizeCursorHV);
#endif
 
  TLayoutWindow::CleanupWindow();
}
 
//
/// Sets data member 'PaneSplitterResizing' to indicate that contained splitters
/// should adjust themselves according to their percentage.
//
void
TPaneSplitter::EvSize(uint sizeType, const TSize& size)
{
  PaneSplitterResizing = true;
  TLayoutWindow::EvSize(sizeType, size);
  PaneSplitterResizing = false;
}
 
//
/// Called by TSplitter when it needs to draw itself. The default behavior provided
/// in this base class is to draw a 3dface splitter.
//
void
TPaneSplitter::DrawSplitter(TDC& dc, const TRect& splitter)
{
  dc.TextRect(splitter, TColor::Sys3dFace);
}
 
//
/// Splits given pane, 'target', with 'newPane', in either the vertical or
/// horizontal direction. Creates a new splitter.
//
bool
TPaneSplitter::SplitPane(TWindow* target, TWindow* newPane,
                         TSplitDirection splitDir, float percent)
{
  PRECONDITION(target);
  PRECONDITION(target != newPane);
 
  if (GetFirstChild() == 0) {     // if no panes.
    TLayoutMetrics  lmOfTarget;
 
    GetDefLM(lmOfTarget);
    target->SetParent(this);
    target->Create();
    SetChildLayoutMetrics(*target, lmOfTarget);
    Layout();
  }
 
  if (newPane) {
    if (!HasPane(target))
      return false;
 
    TSplitter*      splitter;
    TLayoutWindow*  parentSplitter = LAYOUTWINDOW(target->GetParentO());
 
    if (parentSplitter == this) {   // if first split.
      if (splitDir == psHorizontal)
        splitter = new THSplitter(target->GetParentO(), this, percent);
      else
        splitter = new TVSplitter(target->GetParentO(), this, percent);
      splitter->Create();
      splitter->SetPercent(percent);
 
      TLayoutMetrics lm = splitter->Setup(target, newPane, percent);
      parentSplitter->SetChildLayoutMetrics(*splitter, lm);
    }
    else {
      // Ask splitter to split itself.
      //
      SPLITTER(parentSplitter)->Split(target, newPane, splitDir, percent);
    }
    parentSplitter->Layout();
  }
  return true;
}
 
//
/// Removes given pane from TPaneSplitter, deleting it if requested.
/// This operation has the side effect of removing the splitter it was
/// contained in.
//
bool
TPaneSplitter::RemovePane(TWindow* pane, TPaneSplitter::TDelete dt)
{
  TLayoutWindow* layoutWin = DoRemovePane(pane, dt);
  if (layoutWin) {
    PaneSplitterResizing = true;
    layoutWin->Layout();
    PaneSplitterResizing = false;
    return true;
  }
  return false;
}
 
//
/// Replaces 'target' pane (must exist) with 'newPane' (does not exist). 'target'
/// may be deleted; it depends on 'dt'.
//
bool
TPaneSplitter::ReplacePane(TWindow* target, TWindow* newPane,
                           TPaneSplitter::TDelete dt)
{
  if (!HasPane(target) || HasPane(newPane)) // 'newPane' should not exist.
    return false;
 
  if (target->CanClose()) {     // 'newPane' takes on target's layout metrics.
    TLayoutMetrics  lmOfTarget;
    TLayoutMetrics  lmOfOther;
    TLayoutWindow*  splitter = LAYOUTWINDOW(target->GetParentO());
    TWindow*        pane1 = splitter->GetFirstChild();
    TWindow*        pane2 = 0;
 
    if (SPLITTER(splitter)) {
      pane1 = SPLITTER(splitter)->Pane1();
      pane2 = SPLITTER(splitter)->Pane2();
    }
    splitter->GetChildLayoutMetrics(*target, lmOfTarget);
 
    if (pane1 == target && pane2) {
      splitter->GetChildLayoutMetrics(*pane2, lmOfOther);
      if (lmOfOther.X.RelWin == target)
        lmOfOther.X.RelWin = newPane;
      else
        lmOfOther.Y.RelWin = newPane;
      splitter->SetChildLayoutMetrics(*pane2, lmOfOther);
    }
    newPane->SetParent(splitter);
    newPane->Create();
    splitter->SetChildLayoutMetrics(*newPane, lmOfTarget);
    splitter->RemoveChildLayoutMetrics(*target);
    DestroyPane(target, dt);
    splitter->Layout();
    return true;
  }
  return false;
}
 
//
/// Swaps given panes (must exist). Panes take on each others' layout metrics.
//
bool
TPaneSplitter::SwapPanes(TWindow* pane1, TWindow* pane2)
{
  if (!HasPane(pane1) || !HasPane(pane2))
    return false;
 
  TSplitter* splitter1 = SPLITTER(pane1->GetParentO());
  TSplitter* splitter2 = SPLITTER(pane2->GetParentO());
 
  if (splitter1 != splitter2) {
    TLayoutMetrics  lmOfPane1;
    TLayoutMetrics  lmOfPane2;
    TLayoutMetrics  lmOfOther;
    TWindow*        paneA = splitter1->Pane1();
    TWindow*        paneB = splitter1->Pane2();
 
    splitter1->GetChildLayoutMetrics(*pane1, lmOfPane1);
    splitter2->GetChildLayoutMetrics(*pane2, lmOfPane2);
 
    if (paneA == pane1) {   // if top or left pane.
      splitter1->GetChildLayoutMetrics(*paneB, lmOfOther);
      pane1->SetParent(0);
      if (lmOfOther.X.RelWin == pane1)
        lmOfOther.X.RelWin = pane2;
      else
        lmOfOther.Y.RelWin = pane2;
      splitter1->SetChildLayoutMetrics(*paneB, lmOfOther);
    }
 
    paneA = splitter2->Pane1();
    paneB = splitter2->Pane2();
    if (paneA == pane2) {   // if top or left pane.
      splitter2->GetChildLayoutMetrics(*paneB, lmOfOther);
      pane2->SetParent(0);
      if (lmOfOther.X.RelWin == pane2)
        lmOfOther.X.RelWin = pane1;
      else
        lmOfOther.Y.RelWin = pane1;
      splitter2->SetChildLayoutMetrics(*paneB, lmOfOther);
    }
    pane1->SetParent(splitter2);
    pane2->SetParent(splitter1);
    splitter1->SetChildLayoutMetrics(*pane2, lmOfPane1);
    splitter2->SetChildLayoutMetrics(*pane1, lmOfPane2);
    splitter1->Layout();
    splitter2->Layout();
  }
  else {
    TLayoutWindow*  lw = LAYOUTWINDOW(pane1->GetParentO());
    TLayoutMetrics  lmOfPane1;
    TLayoutMetrics  lmOfPane2;
 
    lw->GetChildLayoutMetrics(*pane1, lmOfPane1);
    lw->GetChildLayoutMetrics(*pane2, lmOfPane2);
 
    if (lmOfPane1.X.RelWin == pane2)
      lmOfPane1.X.RelWin = pane1;
    else if (lmOfPane2.X.RelWin == pane1)
      lmOfPane2.X.RelWin = pane2;
    else if (lmOfPane1.Y.RelWin == pane2)
      lmOfPane1.Y.RelWin = pane1;
    else
      lmOfPane2.Y.RelWin = pane2;
 
    lw->SetChildLayoutMetrics(*pane1, lmOfPane2);
    lw->SetChildLayoutMetrics(*pane2, lmOfPane1);
    lw->Layout();
  }
  return true;
}
 
//
/// Iterates over each pane. If 'callback' returns 0, then iteration stops.
//
void
TPaneSplitter::ForEachPane(TPaneSplitter::TForEachPaneCallback callback,
                           void* p)
{
  ForEachObject(GetFirstChild(), &TPaneSplitter::DoForEachPane,
                (void*)callback, p);  // !CQ hack cast
}
 
//
/// Returns the number of panes in TPaneSplitter.
//
int
TPaneSplitter::PaneCount()
{
  int nPanes = 0;
 
  ForEachObject(GetFirstChild(), &TPaneSplitter::DoPaneCount, &nPanes, 0);
  return nPanes;
}
 
//
/// Removes all the panes (and their splitters). If any pane can't close, the
/// operation is aborted.
//
void
TPaneSplitter::RemoveAllPanes(TDelete dt)
{
  TBaseList<TWindow*>    wList;
 
  // Remove and delete (depending on 'dt') all panes.
  //
  ForEachObject(GetFirstChild(), &TPaneSplitter::GetPanes, &wList, 0);
  TBaseList<TWindow*>::Iterator wListIter(wList);
 
  // check to see if a pane can't close, if so abort operation.
  //
  while(wListIter){
    if (!(*wListIter)->CanClose())
      return;
    wListIter++;
  }
  wListIter.Restart();
  while (wListIter){    // remove all the panes.
    RemovePane(*wListIter, dt);
    wListIter++;
  }
}
 
//
/// Sets the splitter width and adjusts all splitters. Takes effect immediately.
//
int
TPaneSplitter::SetSplitterWidth(int newWidth)
{
  int oldWidth = SplitterWidth;
  int widthDiff = newWidth - SplitterWidth;
 
  SplitterWidth = newWidth;
  ForEachObject(GetFirstChild(), &TPaneSplitter::AdjSplitterWidth, &widthDiff,
                0);
  return oldWidth;
}
 
//
/// Moves 'pane' a given distance. If 'pane' does not exist, or there are no
/// splitters, or removal of a pane has failed, then false is returned. Otherwise,
/// true is returned.
//
bool
TPaneSplitter::MoveSplitter(TWindow* pane, int dist)
{
  if (!HasPane(pane) || pane->GetParentO() == this )
    return false;
 
  TSplitter*    splitter = SPLITTER(pane->GetParentO());
  TSplitterIndicator* si = splitter->CreateSplitterIndicator();
  si->SetCushion( SplitterCushion );
 
  SplitterIndicatorList->Flush(true);
  SplitterIndicatorList->PushBack(si);
  si->Move(dist);
  if (RemovePanes() == 0) {
    MoveSplitters();
    SplitterIndicatorList->Flush(true);
    return true;
  }
  return false;
}
 
//
// Private Member Functions...
//
 
//
// Notify indicator mgr to move the indicators.
//
void
TPaneSplitter::MouseMoved(const TPoint& point)
{
  if (Dragging)
    SplitterIndicatorMgr.MoveIndicators(point);
}
 
//
// Set capture (for mouse dragging) and notify indicator mgr that
// we are starting to move the indicators.
//
void
TPaneSplitter::StartSplitterMove(TSplitter* splitter, const TPoint& point)
{
  Dragging = true;
  splitter->SetCapture();
  SplitterIndicatorMgr.StartMove(*SplitterIndicatorList, point);
}
 
//
// Release the capture and notify indicator mgr that we have stopped moving
// the indicators.  Remove any panes that were 'covered' by the move.
// Finally, move the splitters.
//
void
TPaneSplitter::EndSplitterMove(const TPoint& /*point*/)
{
  if( !Dragging )
    return;
  Dragging = false;
  ReleaseCapture();
  SplitterIndicatorMgr.EndMove();
  if (RemovePanes() == 0) {
    MoveSplitters();
    SplitterIndicatorList->Flush(true);
  }
}
 
//
// Set the appropriate cursor depending on the number of splitters
// that will be moved.
//
void
TPaneSplitter::SetSplitterMoveCursor(TSplitter* splitter, const TPoint& point)
{
  if (!Dragging)
    FindIntersectingSplitters(point);
 
  if (SplitterIndicatorList->NSplitterIndicators() > 1)
    ::SetCursor(ResizeCursorHV);
  else if (splitter->SplitDirection() == psHorizontal)
    ::SetCursor(ResizeCursorH);
  else
    ::SetCursor(ResizeCursorV);
}
 
//
// Private structure for splitter and pane traversal.
//
struct TTraversalRec {
  TTraversalRec() : Cnt(0), Object(0) {}
  TTraversalRec(TWindow* o) : Cnt(0), Object(o) {}
  TTraversalRec(const TTraversalRec& r) : Cnt(r.Cnt), Object(r.Object) {}
 
  int operator == (const TTraversalRec& r) const { return Object == r.Object; }
  int operator < (const TTraversalRec& r) const { return Object < r.Object; }
  TTraversalRec& operator = (const TTraversalRec& r);
 
  char              Cnt;
  TWindow*          Object;
};
 
TTraversalRec&
TTraversalRec::operator = (const TTraversalRec& r)
{
  Cnt = r.Cnt; Object = r.Object;
  return *this;
}
 
//
// Iterate over the splitters and panes, calling 'callback' on each.
// allows for 2 parameters to be passed.  Traverses the objects in
// one of three order: InOrder, PreOrder and PostOrder.
//
void
TPaneSplitter::ForEachObject(TWindow* o, TForEachObjectCallback callback,
                             void* p1, void* p2, TTraversalOrder order)
{
  if (!o)
    return;
 
  TBaseList<TTraversalRec> tStack;
 
  TTraversalRec         trec;
  bool                  done = false;
 
  tStack.Push(TTraversalRec(o));
  while (!done) {
    trec = tStack.Pop();
    //trec = tStack.Top();
    //delete tStack.Pop();
    trec.Cnt++;
    if ((order == psPreOrder && trec.Cnt == 1) ||
        (order == psInOrder && trec.Cnt == 2)  ||
        (order == psPostOrder && trec.Cnt == 3))
      done = !(this->*callback)(trec.Object, p1, p2);
 
    if (!done) {
      if (trec.Cnt != 3) {
        tStack.Push(TTraversalRec(trec));
        if (trec.Cnt == 1 && SPLITTER(trec.Object))
          tStack.Push(TTraversalRec(SPLITTER(trec.Object)->Pane1()));
        else if (trec.Cnt == 2 && SPLITTER(trec.Object) &&
                 SPLITTER(trec.Object)->Pane2())
          tStack.Push(TTraversalRec(SPLITTER(trec.Object)->Pane2()));
      }
      done = tStack.Empty();
    }
  }
}
 
//
// Set default TLayoutMetrics.  Everything relative to parent.
//
void
TPaneSplitter::GetDefLM(TLayoutMetrics& lm)
{
  lm.SetMeasurementUnits(lmPixels);
  lm.X.SameAs(lmParent, lmLeft);
  lm.Y.SameAs(lmParent, lmTop);
  lm.Width.Set(lmRight, lmSameAs, lmParent, lmRight);
  lm.Height.Set(lmBottom, lmSameAs, lmParent, lmBottom);
}
 
//
// Return true if this TPaneSplitter contains 'p' (pane or splitter).
//
bool
TPaneSplitter::HasPane(TWindow* p)
{
  TWindow* parent = p->GetParentO();
  while (parent) {
    if (parent == this)
      return true;
    parent = parent->GetParentO();
  }
  return false;
}
 
//
// Do the work of removing given pane.
//
TLayoutWindow*
TPaneSplitter::DoRemovePane(TWindow* pane, TPaneSplitter::TDelete dt)
{
  if (!HasPane(pane) || !pane->CanClose())
    return 0;
 
  TSplitter*        splitter = SPLITTER(pane->GetParentO());
  TLayoutWindow*    retval = this;
 
  if (splitter) {
    retval = splitter->RemovePane(pane, dt);
    splitter->Destroy();
    delete splitter;
  }
  else {
    RemoveChildLayoutMetrics(*pane);
    DestroyPane(pane, dt);
  }
  return retval;
}
 
//
// Find intersecting splitters.  Called when splitters will be moved.
//
void
TPaneSplitter::FindIntersectingSplitters(const TPoint& point)
{
  TPoint p = point;
 
  SplitterIndicatorList->Flush(true);
  ForEachObject(GetFirstChild(), &TPaneSplitter::DoFindIntersectingSplitters,
                SplitterIndicatorList, &p);
}
 
//
// Remove any panes 'covered' as a result of a splitter move.
//
int
TPaneSplitter::RemovePanes()
{
  TSplitterIndicatorList          tempList;   // don't process indicators.
  TSplitterIndicatorListIterator  iter(*SplitterIndicatorList);
  TSplitterIndicator*             si;
  int                             nPanesNotRemoved = 0;
 
  while(iter){
    si = iter++;
 
    if(!tempList.Find(si)){   // if indicator not in list then process it.
      TRect               area = si->CalcAreaOfSplitterMove();
      TBaseList<TWindow*> wList; // list of panes to remove.
      ForEachObject(GetFirstChild(), &TPaneSplitter::GetListOfPanesToRemove,
                    &wList, &area);
      TBaseList<TWindow*>::Iterator listIter(wList);
      while(listIter){
        TWindow* pane = listIter++;
        TSplitterIndicator* i;
        if((i = SplitterIndicatorList->FindIndicatorWithSplitter(
              SPLITTER(pane->GetParentO()))) != 0)
          tempList.PushBack(i);
        if (!RemovePane(pane)) {
          tempList.PushBack(i);
          nPanesNotRemoved++;
          break;
        }
      }
    }
  }
  // remove panes not to be moved from list.
  for(TSplitterIndicatorListIterator iter1(tempList);iter1;iter1++){
    delete *iter1;
    SplitterIndicatorList->DetachItem(iter1.Current());
  }
 
  return nPanesNotRemoved;
}
 
//
// Move all splitters.
//
void
TPaneSplitter::MoveSplitters()
{
  for(TSplitterIndicatorListIterator iter(*SplitterIndicatorList);iter;iter++){
    TSplitterIndicator* si = iter.Current();
    si->GetSplitter()->Move(si->GetDistMoved());
    si->GetSplitter()->Layout();
  }
}
 
//
// Destroy a pane, deleting the OWL object if requested
//
void
TPaneSplitter::DestroyPane(TWindow* pane, TDelete dt)
{
  pane->ShowWindow(SW_HIDE);    // so user can't see.
  pane->SetParent(0);
  pane->Destroy();
  if (DelObj(dt))
    delete pane;
}
 
//
// ForEachObject callbacks...
//
 
//
// Iterate over all panes.
//
int
TPaneSplitter::DoForEachPane(TWindow* o, void *p1, void*p2)
{
  if (!SPLITTER(o))
    return ((TForEachPaneCallback)p1)(*o, p2);
  return 1;
}
 
//
// Find intersecting splitters. Determine which splitters to move.
//
int
TPaneSplitter::DoFindIntersectingSplitters(TWindow* o, void *p1, void*p2)
{
  TSplitter* splitter = SPLITTER(o);
  if (splitter) {
    TSplitterIndicator* i = splitter->CreateSplitterIndicator();
    i->SetCushion( SplitterCushion );
    if (i->CouldContain(*(TPoint*)p2))
      ((TSplitterIndicatorList*)p1)->PushBack(i);
    else
      delete i;
  }
  return 1;
}
 
//
// Get a list of panes that will be removed as a result of a splitter move.
//
int
TPaneSplitter::GetListOfPanesToRemove(TWindow* o, void *p1, void*p2)
{
  if (!SPLITTER(o)) {
    TRect r = o->GetWindowRect();
    if ((*(TRect*)p2).Contains(r))
      ((TBaseList<TWindow*>*)p1)->PushBack(o);
  }
  return 1;
}
 
//
// Change the width of every splitter.
//
int
TPaneSplitter::AdjSplitterWidth(TWindow* o, void *p1, void*)
{
  TSplitter* splitter = SPLITTER(o);
 
  if (splitter)
    splitter->AdjSplitterWidth(*(int *)p1);
  return 1;
}
 
//
// Calculate number of panes.
//
int
TPaneSplitter::DoPaneCount(TWindow* o, void *p1, void*)
{
  if (!SPLITTER(o))
    (*(int*)p1)++;
  return 1;
}
 
//
// Get a list of all the panes.
//
int
TPaneSplitter::GetPanes(TWindow* o, void *p1, void*)
{
  if (!SPLITTER(o))
    ((TBaseList<TWindow*>*)p1)->PushBack(o);
  return 1;
}
 
//
// Get a list of all splitters.
//
int
TPaneSplitter::GetSplitters(TWindow* o, void* p1, void*)
{
  if (SPLITTER(o))
    ((TBaseList<TWindow*>*)p1)->PushBack(o);
  return 1;
}
 
} // OWL namespace
/* ========================================================================== */
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: ResizeCursorH, ResizeCursorV, ResizeCursorHV.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: ResizeCursorH, ResizeCursorV, ResizeCursorHV.

V1051 Consider checking for misprints. It's possible that the 'paneB' should be checked here.

V522 There might be dereferencing of a potential null pointer 'retval'.

V522 There might be dereferencing of a potential null pointer 'parentSplitter'.

V522 There might be dereferencing of a potential null pointer 'splitter'.

V522 There might be dereferencing of a potential null pointer 'splitter1'.

V522 There might be dereferencing of a potential null pointer 'splitter2'.

V522 There might be dereferencing of a potential null pointer 'lw'.

V522 There might be dereferencing of a potential null pointer 'splitter'.

V522 There might be dereferencing of a potential null pointer.

V1004 The 'target' pointer was used unsafely after it was verified against nullptr. Check lines: 1111, 1118.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'wListIter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'wListIter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter1' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iter' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V807 Decreased performance. Consider creating a reference to avoid using the 'p1->GetWindowAttr()' expression repeatedly.

V807 Decreased performance. Consider creating a reference to avoid using the 'p1->GetWindowAttr()' expression repeatedly.