// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fwl/core/fwl_gridimp.h"

#include "xfa/fwl/core/cfwl_message.h"
#include "xfa/fwl/core/cfwl_widgetimpproperties.h"
#include "xfa/fwl/core/fwl_contentimp.h"
#include "xfa/fwl/core/fwl_noteimp.h"
#include "xfa/fwl/core/fwl_targetimp.h"
#include "xfa/fwl/core/fwl_threadimp.h"
#include "xfa/fwl/core/fwl_widgetimp.h"
#include "xfa/fxgraphics/cfx_color.h"
#include "xfa/fxgraphics/cfx_path.h"

// static
IFWL_Grid* IFWL_Grid::Create(const CFWL_WidgetImpProperties& properties) {
  IFWL_Grid* pGrid = new IFWL_Grid;
  CFWL_GridImp* pGridImpl = new CFWL_GridImp(properties, nullptr);
  pGrid->SetImpl(pGridImpl);
  pGridImpl->SetInterface(pGrid);
  return pGrid;
}
IFWL_Grid::IFWL_Grid() {}
FWL_HGRIDCOLROW IFWL_Grid::InsertColRow(FX_BOOL bColumn, int32_t nIndex) {
  return static_cast<CFWL_GridImp*>(GetImpl())->InsertColRow(bColumn, nIndex);
}
int32_t IFWL_Grid::CountColRows(FX_BOOL bColumn) {
  return static_cast<CFWL_GridImp*>(GetImpl())->CountColRows(bColumn);
}
FWL_HGRIDCOLROW IFWL_Grid::GetColRow(FX_BOOL bColumn, int32_t nIndex) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetColRow(bColumn, nIndex);
}
int32_t IFWL_Grid::GetIndex(FWL_HGRIDCOLROW hColRow) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetIndex(hColRow);
}
FX_FLOAT IFWL_Grid::GetSize(FWL_HGRIDCOLROW hColRow, FWL_GRIDUNIT& eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetSize(hColRow, eUnit);
}
FWL_ERR IFWL_Grid::SetSize(FWL_HGRIDCOLROW hColRow,
                           FX_FLOAT fSize,
                           FWL_GRIDUNIT eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->SetSize(hColRow, fSize, eUnit);
}
FX_FLOAT IFWL_Grid::GetMinSize(FWL_HGRIDCOLROW hColRow, FWL_GRIDUNIT& eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetMinSize(hColRow, eUnit);
}
FWL_ERR IFWL_Grid::SetMinSize(FWL_HGRIDCOLROW hColRow,
                              FX_FLOAT fSize,
                              FWL_GRIDUNIT eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetMinSize(hColRow, fSize, eUnit);
}
FX_FLOAT IFWL_Grid::GetMaxSize(FWL_HGRIDCOLROW hColRow, FWL_GRIDUNIT& eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetMaxSize(hColRow, eUnit);
}
FWL_ERR IFWL_Grid::SetMaxSize(FWL_HGRIDCOLROW hColRow,
                              FX_FLOAT fSize,
                              FWL_GRIDUNIT eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetMaxSize(hColRow, fSize, eUnit);
}
FX_BOOL IFWL_Grid::DeleteColRow(FWL_HGRIDCOLROW hColRow) {
  return static_cast<CFWL_GridImp*>(GetImpl())->DeleteColRow(hColRow);
}
FX_BOOL IFWL_Grid::IsColumn(FWL_HGRIDCOLROW hColRow) {
  return static_cast<CFWL_GridImp*>(GetImpl())->IsColumn(hColRow);
}
int32_t IFWL_Grid::GetWidgetPos(IFWL_Widget* pWidget, FX_BOOL bColumn) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetWidgetPos(pWidget, bColumn);
}
FWL_ERR IFWL_Grid::SetWidgetPos(IFWL_Widget* pWidget,
                                int32_t iPos,
                                FX_BOOL bColumn) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetWidgetPos(pWidget, iPos, bColumn);
}
int32_t IFWL_Grid::GetWidgetSpan(IFWL_Widget* pWidget, FX_BOOL bColumn) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetWidgetSpan(pWidget, bColumn);
}
FWL_ERR IFWL_Grid::SetWidgetSpan(IFWL_Widget* pWidget,
                                 int32_t iSpan,
                                 FX_BOOL bColumn) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetWidgetSpan(pWidget, iSpan, bColumn);
}
FX_FLOAT IFWL_Grid::GetWidgetSize(IFWL_Widget* pWidget,
                                  FWL_GRIDSIZE eSize,
                                  FWL_GRIDUNIT& eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->GetWidgetSize(pWidget, eSize, eUnit);
}
FWL_ERR IFWL_Grid::SetWidgetSize(IFWL_Widget* pWidget,
                                 FWL_GRIDSIZE eSize,
                                 FX_FLOAT fSize,
                                 FWL_GRIDUNIT eUit) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetWidgetSize(pWidget, eSize, fSize, eUit);
}
FX_BOOL IFWL_Grid::GetWidgetMargin(IFWL_Widget* pWidget,
                                   FWL_GRIDMARGIN eMargin,
                                   FX_FLOAT& fMargin) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->GetWidgetMargin(pWidget, eMargin, fMargin);
}
FWL_ERR IFWL_Grid::SetWidgetMargin(IFWL_Widget* pWidget,
                                   FWL_GRIDMARGIN eMargin,
                                   FX_FLOAT fMargin) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->SetWidgetMargin(pWidget, eMargin, fMargin);
}
FWL_ERR IFWL_Grid::RemoveWidgetMargin(IFWL_Widget* pWidget,
                                      FWL_GRIDMARGIN eMargin) {
  return static_cast<CFWL_GridImp*>(GetImpl())
      ->RemoveWidgetMargin(pWidget, eMargin);
}
FX_FLOAT IFWL_Grid::GetGridSize(FWL_GRIDSIZE eSize, FWL_GRIDUNIT& eUnit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->GetGridSize(eSize, eUnit);
}
FWL_ERR IFWL_Grid::SetGridSize(FWL_GRIDSIZE eSize,
                               FX_FLOAT fSize,
                               FWL_GRIDUNIT eUit) {
  return static_cast<CFWL_GridImp*>(GetImpl())->SetGridSize(eSize, fSize, eUit);
}

CFWL_GridImp::CFWL_GridImp(const CFWL_WidgetImpProperties& properties,
                           IFWL_Widget* pOuter)
    : CFWL_ContentImp(properties, pOuter) {
  m_Size[FWL_GRIDSIZE_Width].eUnit = FWL_GRIDUNIT_Auto;
  m_Size[FWL_GRIDSIZE_Width].fLength = 0;
  m_Size[FWL_GRIDSIZE_Height].eUnit = FWL_GRIDUNIT_Auto;
  m_Size[FWL_GRIDSIZE_Height].fLength = 0;
  m_Size[FWL_GRIDSIZE_MinWidth].eUnit = FWL_GRIDUNIT_Fixed;
  m_Size[FWL_GRIDSIZE_MinWidth].fLength = 0;
  m_Size[FWL_GRIDSIZE_MaxWidth].eUnit = FWL_GRIDUNIT_Infinity;
  m_Size[FWL_GRIDSIZE_MaxWidth].fLength = 0;
  m_Size[FWL_GRIDSIZE_MinHeight].eUnit = FWL_GRIDUNIT_Fixed;
  m_Size[FWL_GRIDSIZE_MinHeight].fLength = 0;
  m_Size[FWL_GRIDSIZE_MaxHeight].eUnit = FWL_GRIDUNIT_Infinity;
  m_Size[FWL_GRIDSIZE_MaxHeight].fLength = 0;
}
CFWL_GridImp::~CFWL_GridImp() {
  int32_t iCount = m_Columns.GetSize();
  for (int32_t i = 0; i < iCount; i++) {
    delete static_cast<CFWL_GridColRow*>(m_Columns[i]);
  }
  m_Columns.RemoveAll();
  iCount = m_Rows.GetSize();
  for (int32_t j = 0; j < iCount; j++) {
    delete static_cast<CFWL_GridColRow*>(m_Rows[j]);
  }
  m_Rows.RemoveAll();
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget;
    CFWL_GridWidgetInfo* pInfo;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    delete pInfo;
  }
  m_mapWidgetInfo.RemoveAll();
  delete m_pDelegate;
  m_pDelegate = nullptr;
}
FWL_ERR CFWL_GridImp::GetClassName(CFX_WideString& wsClass) const {
  wsClass = FWL_CLASS_Grid;
  return FWL_ERR_Succeeded;
}
uint32_t CFWL_GridImp::GetClassID() const {
  return FWL_CLASSHASH_Grid;
}
FWL_ERR CFWL_GridImp::Initialize() {
  if (CFWL_ContentImp::Initialize() != FWL_ERR_Succeeded)
    return FWL_ERR_Indefinite;
  m_pDelegate = new CFWL_GridImpDelegate(this);
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::Finalize() {
  if (CFWL_ContentImp::Finalize() != FWL_ERR_Succeeded)
    return FWL_ERR_Indefinite;
  delete m_pDelegate;
  m_pDelegate = nullptr;
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) {
  if (bAutoSize) {
    rect.left = 0;
    rect.top = 0;
    rect.width = ProcessUnCertainColumns();
    rect.height = ProcessUnCertainRows();
  } else {
    rect = m_pProperties->m_rtWidget;
  }
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::SetWidgetRect(const CFX_RectF& rect) {
  CFWL_WidgetImp::SetWidgetRect(rect);
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::Update() {
  if (IsLocked()) {
    return FWL_ERR_Indefinite;
  }
  ProcessColumns(m_pProperties->m_rtWidget.width);
  ProcessRows(m_pProperties->m_rtWidget.height);
  SetAllWidgetsRect();
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::DrawWidget(CFX_Graphics* pGraphics,
                                 const CFX_Matrix* pMatrix) {
  if (!pGraphics)
    return FWL_ERR_Indefinite;
  if ((m_pProperties->m_dwStyleExes & FWL_GRIDSTYLEEXT_ShowGridLines) == 0) {
    return FWL_ERR_Succeeded;
  }
  pGraphics->SaveGraphState();
  if (pMatrix) {
    pGraphics->ConcatMatrix(pMatrix);
  }
  {
    FX_BOOL bDrawLine = FALSE;
    CFX_Path path;
    path.Create();
    int32_t iColumns = m_Columns.GetSize();
    for (int32_t i = 1; i < iColumns; i++) {
      CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Columns[i]);
      if (!pColRow) {
        continue;
      }
      bDrawLine = TRUE;
      path.AddLine(pColRow->m_fActualPos, 0, pColRow->m_fActualPos,
                   m_pProperties->m_rtWidget.height);
    }
    int32_t iRows = m_Rows.GetSize();
    for (int32_t j = 1; j < iRows; j++) {
      CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Rows[j]);
      if (!pColRow) {
        continue;
      }
      bDrawLine = TRUE;
      path.AddLine(0, pColRow->m_fActualPos, m_pProperties->m_rtWidget.width,
                   pColRow->m_fActualPos);
    }
    if (bDrawLine) {
      CFX_Color cr(0xFFFF0000);
      pGraphics->SetStrokeColor(&cr);
      pGraphics->StrokePath(&path);
    }
  }
  pGraphics->RestoreGraphState();
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::InsertWidget(IFWL_Widget* pChild, int32_t nIndex) {
  if (!pChild)
    return FWL_ERR_Indefinite;
  CFWL_ContentImp::InsertWidget(pChild, nIndex);
  if (!m_mapWidgetInfo.GetValueAt(pChild)) {
    CFWL_GridWidgetInfo* pInfo = new CFWL_GridWidgetInfo;
    m_mapWidgetInfo.SetAt(pChild, pInfo);
    m_Widgets.Add(pChild);
  }
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::RemoveWidget(IFWL_Widget* pWidget) {
  if (!pWidget)
    return FWL_ERR_Indefinite;
  CFWL_ContentImp::RemoveWidget(pWidget);
  if (CFWL_GridWidgetInfo* pInfo = static_cast<CFWL_GridWidgetInfo*>(
          m_mapWidgetInfo.GetValueAt(pWidget))) {
    m_mapWidgetInfo.RemoveKey(pWidget);
    delete pInfo;
    int32_t nIndex = m_Widgets.Find(pWidget);
    m_Widgets.RemoveAt(nIndex, 1);
  }
  return FWL_ERR_Succeeded;
}
FWL_HGRIDCOLROW CFWL_GridImp::InsertColRow(FX_BOOL bColumn, int32_t nIndex) {
  if (bColumn) {
    if (nIndex < 0 || nIndex > m_Columns.GetSize()) {
      nIndex = m_Columns.GetSize();
    }
    CFWL_GridColRow* pColumn = new CFWL_GridColRow;
    m_Columns.InsertAt(nIndex, pColumn, 1);
    return (FWL_HGRIDCOLROW)pColumn;
  }
  if (nIndex < 0 || nIndex > m_Rows.GetSize()) {
    nIndex = m_Rows.GetSize();
  }
  CFWL_GridColRow* pRow = new CFWL_GridColRow;
  m_Rows.InsertAt(nIndex, pRow, 1);
  return (FWL_HGRIDCOLROW)pRow;
}
int32_t CFWL_GridImp::CountColRows(FX_BOOL bColumn) {
  if (bColumn) {
    return m_Columns.GetSize();
  }
  return m_Rows.GetSize();
}
FWL_HGRIDCOLROW CFWL_GridImp::GetColRow(FX_BOOL bColumn, int32_t nIndex) {
  if (bColumn) {
    if (nIndex < 0 || nIndex >= m_Columns.GetSize()) {
      return NULL;
    }
    return (FWL_HGRIDCOLROW)m_Columns[nIndex];
  }
  if (nIndex < 0 || nIndex >= m_Rows.GetSize()) {
    return NULL;
  }
  return (FWL_HGRIDCOLROW)m_Rows[nIndex];
}
int32_t CFWL_GridImp::GetIndex(FWL_HGRIDCOLROW hColRow) {
  if (IsColumn(hColRow)) {
    return m_Columns.Find(hColRow);
  }
  return m_Rows.Find(hColRow);
}
FX_FLOAT CFWL_GridImp::GetSize(FWL_HGRIDCOLROW hColRow, FWL_GRIDUNIT& eUnit) {
  if (!hColRow)
    return -1;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  eUnit = pColRow->m_Size.eUnit;
  return pColRow->m_Size.fLength;
}
FWL_ERR CFWL_GridImp::SetSize(FWL_HGRIDCOLROW hColRow,
                              FX_FLOAT fSize,
                              FWL_GRIDUNIT eUnit) {
  if (!hColRow)
    return FWL_ERR_Indefinite;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  pColRow->m_Size.eUnit = eUnit;
  pColRow->m_Size.fLength = fSize;
  return FWL_ERR_Succeeded;
}
FX_FLOAT CFWL_GridImp::GetMinSize(FWL_HGRIDCOLROW hColRow,
                                  FWL_GRIDUNIT& eUnit) {
  if (!hColRow)
    return -1;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  eUnit = pColRow->m_MinSize.eUnit;
  return pColRow->m_MinSize.fLength;
}
FWL_ERR CFWL_GridImp::SetMinSize(FWL_HGRIDCOLROW hColRow,
                                 FX_FLOAT fSize,
                                 FWL_GRIDUNIT eUnit) {
  if (!hColRow)
    return FWL_ERR_Indefinite;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  pColRow->m_MinSize.eUnit = eUnit;
  pColRow->m_MinSize.fLength = fSize;
  return FWL_ERR_Succeeded;
}
FX_FLOAT CFWL_GridImp::GetMaxSize(FWL_HGRIDCOLROW hColRow,
                                  FWL_GRIDUNIT& eUnit) {
  if (!hColRow)
    return -1;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  eUnit = pColRow->m_MaxSize.eUnit;
  return pColRow->m_MaxSize.fLength;
}
FWL_ERR CFWL_GridImp::SetMaxSize(FWL_HGRIDCOLROW hColRow,
                                 FX_FLOAT fSize,
                                 FWL_GRIDUNIT eUnit) {
  if (!hColRow)
    return FWL_ERR_Indefinite;
  CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(hColRow);
  pColRow->m_MaxSize.eUnit = eUnit;
  pColRow->m_MaxSize.fLength = fSize;
  return FWL_ERR_Succeeded;
}
FX_BOOL CFWL_GridImp::DeleteColRow(FWL_HGRIDCOLROW hColRow) {
  int32_t nIndex = m_Columns.Find(hColRow);
  if (nIndex >= 0) {
    m_Columns.RemoveAt(nIndex);
    delete reinterpret_cast<CFWL_GridColRow*>(hColRow);
    return TRUE;
  }
  nIndex = m_Rows.Find(hColRow);
  if (nIndex >= 0) {
    delete reinterpret_cast<CFWL_GridColRow*>(hColRow);
    m_Rows.RemoveAt(nIndex);
    return TRUE;
  }
  return FALSE;
}
FX_BOOL CFWL_GridImp::IsColumn(FWL_HGRIDCOLROW hColRow) {
  return m_Columns.Find(hColRow) != -1;
}
int32_t CFWL_GridImp::GetWidgetPos(IFWL_Widget* pWidget, FX_BOOL bColumn) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    return bColumn ? pInfo->m_iColumn : pInfo->m_iRow;
  }
  return -1;
}
FWL_ERR CFWL_GridImp::SetWidgetPos(IFWL_Widget* pWidget,
                                   int32_t iPos,
                                   FX_BOOL bColumn) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    bColumn ? pInfo->m_iColumn = iPos : pInfo->m_iRow = iPos;
  }
  return FWL_ERR_Succeeded;
}
int32_t CFWL_GridImp::GetWidgetSpan(IFWL_Widget* pWidget, FX_BOOL bColumn) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    return bColumn ? pInfo->m_iColumnSpan : pInfo->m_iRowSpan;
  }
  return 0;
}
FWL_ERR CFWL_GridImp::SetWidgetSpan(IFWL_Widget* pWidget,
                                    int32_t iSpan,
                                    FX_BOOL bColumn) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    bColumn ? pInfo->m_iColumnSpan = iSpan : pInfo->m_iRowSpan = iSpan;
  }
  return FWL_ERR_Succeeded;
}
FX_FLOAT CFWL_GridImp::GetWidgetSize(IFWL_Widget* pWidget,
                                     FWL_GRIDSIZE eSize,
                                     FWL_GRIDUNIT& eUnit) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    eUnit = pInfo->m_Size[eSize].eUnit;
    return pInfo->m_Size[eSize].fLength;
  }
  return 0;
}
FWL_ERR CFWL_GridImp::SetWidgetSize(IFWL_Widget* pWidget,
                                    FWL_GRIDSIZE eSize,
                                    FX_FLOAT fSize,
                                    FWL_GRIDUNIT eUit) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    pInfo->m_Size[eSize].fLength = fSize;
    pInfo->m_Size[eSize].eUnit = eUit;
  }
  return FWL_ERR_Succeeded;
}
FX_BOOL CFWL_GridImp::GetWidgetMargin(IFWL_Widget* pWidget,
                                      FWL_GRIDMARGIN eMargin,
                                      FX_FLOAT& fMargin) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    fMargin = pInfo->m_Margin[eMargin];
    return (pInfo->m_dwMarginFlag & (1 << eMargin)) != 0;
  }
  return FALSE;
}
FWL_ERR CFWL_GridImp::SetWidgetMargin(IFWL_Widget* pWidget,
                                      FWL_GRIDMARGIN eMargin,
                                      FX_FLOAT fMargin) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    pInfo->m_Margin[eMargin] = fMargin;
    pInfo->m_dwMarginFlag |= (1 << eMargin);
  }
  return FWL_ERR_Succeeded;
}
FWL_ERR CFWL_GridImp::RemoveWidgetMargin(IFWL_Widget* pWidget,
                                         FWL_GRIDMARGIN eMargin) {
  CFWL_GridWidgetInfo* pInfo =
      static_cast<CFWL_GridWidgetInfo*>(GetWidgetInfo(pWidget));
  if (pInfo) {
    pInfo->m_dwMarginFlag &= ~(1 << eMargin);
  }
  return FWL_ERR_Succeeded;
}
FX_FLOAT CFWL_GridImp::GetGridSize(FWL_GRIDSIZE eSize, FWL_GRIDUNIT& eUnit) {
  eUnit = m_Size[eSize].eUnit;
  return m_Size[eSize].fLength;
}
FWL_ERR CFWL_GridImp::SetGridSize(FWL_GRIDSIZE eSize,
                                  FX_FLOAT fSize,
                                  FWL_GRIDUNIT eUit) {
  m_Size[eSize].fLength = fSize;
  m_Size[eSize].eUnit = eUit;
  return FWL_ERR_Succeeded;
}
CFWL_GridWidgetInfo* CFWL_GridImp::GetWidgetInfo(IFWL_Widget* pWidget) {
  return static_cast<CFWL_GridWidgetInfo*>(m_mapWidgetInfo.GetValueAt(pWidget));
}
void CFWL_GridImp::ProcFixedColRow(CFWL_GridColRow* pColRow,
                                   int32_t nIndex,
                                   FX_FLOAT fColRowSize,
                                   FX_BOOL bColumn) {
  pColRow->m_fActualSize = fColRowSize;
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    void* key = nullptr;
    void* value = nullptr;
    m_mapWidgetInfo.GetNextAssoc(ps, key, value);
    IFWL_Widget* pWidget = static_cast<IFWL_Widget*>(key);
    CFWL_GridWidgetInfo* pInfo = static_cast<CFWL_GridWidgetInfo*>(value);
    if (bColumn) {
      if (pInfo->m_iColumn == nIndex && pInfo->m_iColumnSpan == 1) {
        CalcWidgetWidth(pWidget, pInfo, pColRow->m_fActualSize);
      }
    } else {
      if (pInfo->m_iRow == nIndex && pInfo->m_iRowSpan == 1) {
        CalcWidgetHeigt(pWidget, pInfo, pColRow->m_fActualSize);
      }
    }
  }
}
void CFWL_GridImp::ProcAutoColRow(CFWL_GridColRow* pColRow,
                                  int32_t nIndex,
                                  FX_BOOL bColumn) {
  if (!pColRow)
    return;
  FX_FLOAT fMaxSize = 0, fWidgetSize = 0;
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget = NULL;
    CFWL_GridWidgetInfo* pInfo = NULL;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    if (!pWidget || !pInfo) {
      continue;
    }
    if (bColumn) {
      if (pInfo->m_iColumn != nIndex || pInfo->m_iColumnSpan != 1) {
        continue;
      }
      fWidgetSize = CalcAutoColumnWidgetWidth(pWidget, pInfo);
      if (fMaxSize < fWidgetSize) {
        fMaxSize = fWidgetSize;
      }
    } else {
      if (pInfo->m_iRow != nIndex || pInfo->m_iRowSpan != 1) {
        continue;
      }
      fWidgetSize = CalcAutoColumnWidgetHeight(pWidget, pInfo);
      if (fMaxSize < fWidgetSize) {
        fMaxSize = fWidgetSize;
      }
    }
  }
  SetColRowActualSize(pColRow, fMaxSize);
}
void CFWL_GridImp::ProcScaledColRow(CFWL_GridColRow* pColRow,
                                    int32_t nIndex,
                                    FX_FLOAT fColRowSize,
                                    FX_BOOL bColumn) {
  if (fColRowSize > 0) {
    ProcFixedColRow(pColRow, nIndex, fColRowSize, bColumn);
  }
}
void CFWL_GridImp::CalcWidgetWidth(IFWL_Widget* pWidget,
                                   CFWL_GridWidgetInfo* pInfo,
                                   FX_FLOAT fColunmWidth) {
  if (pInfo->m_Size[FWL_GRIDSIZE_Width].eUnit == FWL_GRIDUNIT_Fixed) {
    SetWidgetActualWidth(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Width].fLength);
  } else {
    FX_FLOAT fWidth = 0;
    FX_FLOAT fLeftMargin = 0, fRightMargin = 0;
    FX_BOOL bLeftMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Left, fLeftMargin);
    FX_BOOL bRightMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Right, fRightMargin);
    if (bLeftMargin && bRightMargin) {
      fWidth = fColunmWidth - fLeftMargin - fRightMargin;
    } else {
      CFX_RectF rtAuto;
      pWidget->GetWidgetRect(rtAuto, TRUE);
      fWidth = rtAuto.Width();
    }
    SetWidgetActualWidth(pInfo, fWidth);
  }
}
void CFWL_GridImp::CalcWidgetHeigt(IFWL_Widget* pWidget,
                                   CFWL_GridWidgetInfo* pInfo,
                                   FX_FLOAT fRowHeigt) {
  if (pInfo->m_Size[FWL_GRIDSIZE_Height].eUnit == FWL_GRIDUNIT_Fixed) {
    SetWidgetActualHeight(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Height].fLength);
  } else {
    FX_FLOAT fHeight = 0;
    FX_FLOAT fTopMargin = 0, fBottomMargin = 0;
    FX_BOOL bTopMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Top, fTopMargin);
    FX_BOOL bBottomMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Bottom, fBottomMargin);
    if (bTopMargin && bBottomMargin) {
      fHeight = fRowHeigt - fTopMargin - fBottomMargin;
    } else {
      CFX_RectF rtAuto;
      pWidget->GetWidgetRect(rtAuto, TRUE);
      fHeight = rtAuto.Height();
    }
    SetWidgetActualHeight(pInfo, fHeight);
  }
}
FX_FLOAT CFWL_GridImp::CalcAutoColumnWidgetWidth(IFWL_Widget* pWidget,
                                                 CFWL_GridWidgetInfo* pInfo) {
  FX_FLOAT fLeftMargin = 0, fRightMargin = 0;
  FX_BOOL bLeftMargin =
      GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Left, fLeftMargin);
  FX_BOOL bRightMargin =
      GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Right, fRightMargin);
  if (pInfo->m_Size[FWL_GRIDSIZE_Width].eUnit == FWL_GRIDUNIT_Fixed) {
    SetWidgetActualWidth(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Width].fLength);
  } else {
    CFX_RectF rtAuto;
    pWidget->GetWidgetRect(rtAuto, TRUE);
    FX_FLOAT fWidth = rtAuto.width;
    SetWidgetActualWidth(pInfo, fWidth);
  }
  FX_FLOAT fTotal = pInfo->m_fActualWidth;
  if (bLeftMargin) {
    fTotal += fLeftMargin;
  }
  if (bRightMargin) {
    fTotal += fRightMargin;
  }
  return fTotal;
}
FX_FLOAT CFWL_GridImp::CalcAutoColumnWidgetHeight(IFWL_Widget* pWidget,
                                                  CFWL_GridWidgetInfo* pInfo) {
  FX_FLOAT fTopMargin = 0, fBottomMargin = 0;
  FX_BOOL bTopMargin = GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Top, fTopMargin);
  FX_BOOL bBottomMargin =
      GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Bottom, fBottomMargin);
  if (pInfo->m_Size[FWL_GRIDSIZE_Height].eUnit == FWL_GRIDUNIT_Fixed) {
    SetWidgetActualHeight(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Height].fLength);
  } else {
    CFX_RectF rtAuto;
    pWidget->GetWidgetRect(rtAuto, TRUE);
    FX_FLOAT fHeight = rtAuto.height;
    SetWidgetActualHeight(pInfo, fHeight);
  }
  FX_FLOAT fTotal = pInfo->m_fActualHeight;
  if (bTopMargin) {
    fTotal += fTopMargin;
  }
  if (bBottomMargin) {
    fTotal += fBottomMargin;
  }
  return fTotal;
}
FX_FLOAT CFWL_GridImp::ProcessColumns(FX_FLOAT fWidth) {
  if (fWidth <= 0) {
    return ProcessUnCertainColumns();
  }
  int32_t iColumns = m_Columns.GetSize();
  if (iColumns < 1) {
    return fWidth;
  }
  FX_FLOAT fFixedWidth = 0;
  FX_FLOAT fAutoWidth = 0;
  CFX_PtrArray autoColumns;
  CFX_PtrArray scaledColumns;
  FX_FLOAT fScaledColumnNum = 0;
  for (int32_t i = 0; i < iColumns; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Columns[i]);
    if (!pColRow) {
      continue;
    }
    switch (pColRow->m_Size.eUnit) {
      case FWL_GRIDUNIT_Fixed: {
        SetColRowActualSize(pColRow, pColRow->m_Size.fLength);
        fFixedWidth += pColRow->m_fActualSize;
        break;
      }
      case FWL_GRIDUNIT_Auto: {
        ProcAutoColRow(pColRow, i, TRUE);
        autoColumns.Add(pColRow);
        break;
      }
      case FWL_GRIDUNIT_Scaled:
      default: {
        fScaledColumnNum += pColRow->m_Size.fLength;
        scaledColumns.Add(pColRow);
        SetColRowActualSize(pColRow, 0);
      }
    }
  }
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget = NULL;
    CFWL_GridWidgetInfo* pInfo = NULL;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    if (!pInfo || pInfo->m_iColumnSpan < 2) {
      continue;
    }
    CFX_PtrArray spanAutoColumns;
    FX_FLOAT fSpanSize = 0;
    int32_t iAutoColRows = 0;
    int32_t iScaledColRows = 0;
    for (int32_t i = 0; i < pInfo->m_iColumnSpan; i++) {
      CFWL_GridColRow* pColumn = reinterpret_cast<CFWL_GridColRow*>(
          GetColRow(TRUE, pInfo->m_iColumn + i));
      if (!pColumn) {
        break;
      }
      fSpanSize += pColumn->m_fActualSize;
      if (pColumn->m_Size.eUnit == FWL_GRIDUNIT_Auto) {
        iAutoColRows++;
        spanAutoColumns.Add(pColumn);
      } else if (pColumn->m_Size.eUnit == FWL_GRIDUNIT_Scaled) {
        iScaledColRows++;
      }
    }
    if (iAutoColRows < 1) {
      continue;
    }
    FX_FLOAT fWidgetWidth = CalcAutoColumnWidgetWidth(pWidget, pInfo);
    if (fWidgetWidth > fSpanSize) {
      if (iScaledColRows > 0) {
      } else {
        SetSpanAutoColRowSize(spanAutoColumns, fWidgetWidth - fSpanSize);
      }
    }
  }
  int32_t iAutoCols = autoColumns.GetSize();
  for (int32_t k = 0; k < iAutoCols; k++) {
    fAutoWidth += static_cast<CFWL_GridColRow*>(autoColumns[k])->m_fActualSize;
  }
  FX_FLOAT fScaledWidth = fWidth - fFixedWidth - fAutoWidth;
  if (fScaledWidth > 0 && fScaledColumnNum > 0) {
    SetScaledColRowsSize(scaledColumns, fScaledWidth, fScaledColumnNum);
  }
  return fWidth;
}
FX_FLOAT CFWL_GridImp::ProcessRows(FX_FLOAT fHeight) {
  if (fHeight <= 0) {
    return ProcessUnCertainRows();
  }
  int32_t iRows = m_Rows.GetSize();
  if (iRows < 1) {
    return fHeight;
  }
  FX_FLOAT fFixedHeight = 0;
  FX_FLOAT fAutoHeigt = 0;
  CFX_PtrArray autoRows;
  CFX_PtrArray scaledRows;
  FX_FLOAT fScaledRowNum = 0;
  for (int32_t i = 0; i < iRows; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Rows[i]);
    if (!pColRow) {
      continue;
    }
    switch (pColRow->m_Size.eUnit) {
      case FWL_GRIDUNIT_Fixed: {
        SetColRowActualSize(pColRow, pColRow->m_Size.fLength);
        fFixedHeight += pColRow->m_fActualSize;
        break;
      }
      case FWL_GRIDUNIT_Auto: {
        ProcAutoColRow(pColRow, i, FALSE);
        autoRows.Add(pColRow);
        break;
      }
      case FWL_GRIDUNIT_Scaled:
      default: {
        fScaledRowNum += pColRow->m_Size.fLength;
        scaledRows.Add(pColRow);
        SetColRowActualSize(pColRow, 0);
        break;
      }
    }
  }
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget = NULL;
    CFWL_GridWidgetInfo* pInfo = NULL;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    if (!pInfo || pInfo->m_iRowSpan < 2) {
      continue;
    }
    CFX_PtrArray spanAutoRows;
    FX_FLOAT fSpanSize = 0;
    int32_t iAutoColRows = 0;
    int32_t iScaledColRows = 0;
    for (int32_t i = 0; i < pInfo->m_iRowSpan; i++) {
      CFWL_GridColRow* pRow = reinterpret_cast<CFWL_GridColRow*>(
          GetColRow(FALSE, pInfo->m_iRow + i));
      if (!pRow) {
        break;
      }
      fSpanSize += pRow->m_fActualSize;
      if (pRow->m_Size.eUnit == FWL_GRIDUNIT_Auto) {
        iAutoColRows++;
        spanAutoRows.Add(pRow);
      } else if (pRow->m_Size.eUnit == FWL_GRIDUNIT_Scaled) {
        iScaledColRows++;
      }
    }
    if (iAutoColRows < 1) {
      continue;
    }
    FX_FLOAT fWidgetHeight = CalcAutoColumnWidgetHeight(pWidget, pInfo);
    if (fWidgetHeight > fSpanSize) {
      if (iScaledColRows > 0) {
      } else {
        SetSpanAutoColRowSize(spanAutoRows, fWidgetHeight - fSpanSize);
      }
    }
  }
  int32_t iAutoRows = autoRows.GetSize();
  for (int32_t k = 0; k < iAutoRows; k++) {
    fAutoHeigt +=
        reinterpret_cast<CFWL_GridColRow*>(autoRows[k])->m_fActualSize;
  }
  FX_FLOAT fScaledHeight = fHeight - fFixedHeight - fAutoHeigt;
  if (fScaledHeight > 0 && fScaledRowNum > 0) {
    SetScaledColRowsSize(scaledRows, fScaledHeight, fScaledRowNum);
  }
  return fHeight;
}
FX_FLOAT CFWL_GridImp::ProcessUnCertainColumns() {
  int32_t iColumns = m_Columns.GetSize();
  if (iColumns < 1) {
    CFWL_GridColRow* pColRow = new CFWL_GridColRow;
    pColRow->m_Size.eUnit = FWL_GRIDUNIT_Auto;
    ProcAutoColRow(pColRow, 0, TRUE);
    FX_FLOAT fWidth = pColRow->m_fActualSize;
    delete pColRow;
    return fWidth;
  }
  FX_FLOAT fFixedWidth = 0;
  CFX_PtrArray autoColumns;
  CFX_PtrArray scaledColumns;
  FX_FLOAT fScaledColumnNum = 0;
  FX_FLOAT fScaledMaxPerWidth = 0;
  for (int32_t i = 0; i < iColumns; i++) {
    CFWL_GridColRow* pColRow = reinterpret_cast<CFWL_GridColRow*>(m_Columns[i]);
    if (!pColRow) {
      continue;
    }
    switch (pColRow->m_Size.eUnit) {
      case FWL_GRIDUNIT_Fixed: {
        SetColRowActualSize(pColRow, pColRow->m_Size.fLength);
        fFixedWidth += pColRow->m_fActualSize;
        break;
      }
      case FWL_GRIDUNIT_Auto: {
        ProcAutoColRow(pColRow, i, TRUE);
        autoColumns.Add(pColRow);
        break;
      }
      case FWL_GRIDUNIT_Scaled:
      default: {
        ProcAutoColRow(pColRow, i, TRUE);
        fScaledColumnNum += pColRow->m_Size.fLength;
        scaledColumns.Add(pColRow);
        if (pColRow->m_Size.fLength <= 0) {
          break;
        }
        FX_FLOAT fPerWidth = pColRow->m_fActualSize / pColRow->m_Size.fLength;
        if (fPerWidth > fScaledMaxPerWidth) {
          fScaledMaxPerWidth = fPerWidth;
        }
      }
    }
  }
  iColumns = scaledColumns.GetSize();
  for (int32_t j = 0; j < iColumns; j++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(scaledColumns[j]);
    if (!pColRow) {
      continue;
    }
    SetColRowActualSize(pColRow, fScaledMaxPerWidth * pColRow->m_Size.fLength);
  }
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget = NULL;
    CFWL_GridWidgetInfo* pInfo = NULL;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    if (!pInfo || pInfo->m_iColumnSpan < 2) {
      continue;
    }
    CFX_PtrArray spanAutoColumns;
    CFX_PtrArray spanScaledColumns;
    FX_FLOAT fSpanSize = 0;
    FX_FLOAT fScaledSum = 0;
    int32_t iAutoColRows = 0;
    int32_t iScaledColRows = 0;
    for (int32_t i = 0; i < pInfo->m_iColumnSpan; i++) {
      CFWL_GridColRow* pColumn = reinterpret_cast<CFWL_GridColRow*>(
          GetColRow(TRUE, pInfo->m_iColumn + i));
      if (!pColumn) {
        break;
      }
      fSpanSize += pColumn->m_fActualSize;
      if (pColumn->m_Size.eUnit == FWL_GRIDUNIT_Auto) {
        iAutoColRows++;
        spanAutoColumns.Add(pColumn);
      } else if (pColumn->m_Size.eUnit == FWL_GRIDUNIT_Scaled) {
        iScaledColRows++;
        fScaledSum += pColumn->m_Size.fLength;
        spanScaledColumns.Add(pColumn);
      }
    }
    if (iAutoColRows < 1 && iScaledColRows < 1) {
      continue;
    }
    FX_FLOAT fWidgetWidth = CalcAutoColumnWidgetWidth(pWidget, pInfo);
    if (fWidgetWidth > fSpanSize) {
      if (iScaledColRows > 0) {
        if (fScaledSum <= 0) {
          continue;
        }
        SetSpanScaledColRowSize(spanScaledColumns, fWidgetWidth - fSpanSize,
                                fScaledSum);
      } else {
        SetSpanAutoColRowSize(spanAutoColumns, fWidgetWidth - fSpanSize);
      }
    }
  }
  FX_FLOAT fAutoWidth = 0;
  int32_t iAutoCols = autoColumns.GetSize();
  for (int32_t m = 0; m < iAutoCols; m++) {
    fAutoWidth += static_cast<CFWL_GridColRow*>(autoColumns[m])->m_fActualSize;
  }
  FX_FLOAT fScaledWidth = 0;
  iColumns = scaledColumns.GetSize();
  for (int32_t n = 0; n < iColumns; n++) {
    fScaledWidth +=
        static_cast<CFWL_GridColRow*>(scaledColumns[n])->m_fActualSize;
  }
  return fFixedWidth + fAutoWidth + fScaledWidth;
}
FX_FLOAT CFWL_GridImp::ProcessUnCertainRows() {
  int32_t iRows = m_Rows.GetSize();
  if (iRows < 1) {
    CFWL_GridColRow* pColRow = new CFWL_GridColRow;
    pColRow->m_Size.eUnit = FWL_GRIDUNIT_Auto;
    ProcAutoColRow(pColRow, 0, FALSE);
    FX_FLOAT fWidth = pColRow->m_fActualSize;
    delete pColRow;
    return fWidth;
  }
  FX_FLOAT fFixedHeight = 0;
  CFX_PtrArray autoRows;
  CFX_PtrArray scaledRows;
  FX_FLOAT fScaledRowNum = 0;
  FX_FLOAT fScaledMaxPerHeight = 0;
  for (int32_t i = 0; i < iRows; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Rows[i]);
    if (!pColRow) {
      continue;
    }
    switch (pColRow->m_Size.eUnit) {
      case FWL_GRIDUNIT_Fixed: {
        SetColRowActualSize(pColRow, pColRow->m_Size.fLength);
        fFixedHeight += pColRow->m_fActualSize;
        break;
      }
      case FWL_GRIDUNIT_Auto: {
        ProcAutoColRow(pColRow, i, FALSE);
        autoRows.Add(pColRow);
        break;
      }
      case FWL_GRIDUNIT_Scaled:
      default: {
        ProcAutoColRow(pColRow, i, FALSE);
        fScaledRowNum += pColRow->m_Size.fLength;
        scaledRows.Add(pColRow);
        if (pColRow->m_Size.fLength > 0) {
          FX_FLOAT fPerHeight =
              pColRow->m_fActualSize / pColRow->m_Size.fLength;
          if (fPerHeight > fScaledMaxPerHeight) {
            fScaledMaxPerHeight = fPerHeight;
          }
        }
        break;
      }
    }
  }
  iRows = scaledRows.GetSize();
  for (int32_t j = 0; j < iRows; j++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(scaledRows[j]);
    if (!pColRow) {
      continue;
    }
    SetColRowActualSize(pColRow, fScaledMaxPerHeight * pColRow->m_Size.fLength);
  }
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    void* key = nullptr;
    void* value = nullptr;
    m_mapWidgetInfo.GetNextAssoc(ps, key, value);
    IFWL_Widget* pWidget = static_cast<IFWL_Widget*>(key);
    CFWL_GridWidgetInfo* pInfo = static_cast<CFWL_GridWidgetInfo*>(value);
    if (pInfo->m_iRowSpan < 2) {
      continue;
    }
    CFX_PtrArray spanAutoRows;
    CFX_PtrArray spanScaledRows;
    FX_FLOAT fSpanSize = 0;
    FX_FLOAT fScaledSum = 0;
    int32_t iAutoColRows = 0;
    int32_t iScaledColRows = 0;
    for (int32_t i = 0; i < pInfo->m_iRowSpan; i++) {
      CFWL_GridColRow* pRow = reinterpret_cast<CFWL_GridColRow*>(
          GetColRow(FALSE, pInfo->m_iRow + i));
      if (!pRow) {
        break;
      }
      fSpanSize += pRow->m_fActualSize;
      if (pRow->m_Size.eUnit == FWL_GRIDUNIT_Auto) {
        iAutoColRows++;
        spanAutoRows.Add(pRow);
      } else if (pRow->m_Size.eUnit == FWL_GRIDUNIT_Scaled) {
        iScaledColRows++;
        fScaledSum += pRow->m_Size.fLength;
        spanScaledRows.Add(pRow);
      }
    }
    if (iAutoColRows < 1 && iScaledColRows < 1) {
      continue;
    }
    FX_FLOAT fWidgetHeight = CalcAutoColumnWidgetHeight(pWidget, pInfo);
    if (fWidgetHeight > fSpanSize) {
      if (iScaledColRows > 0) {
        if (fScaledSum <= 0) {
          continue;
        }
        SetSpanScaledColRowSize(spanScaledRows, fWidgetHeight - fSpanSize,
                                fScaledSum);
      } else {
        SetSpanAutoColRowSize(spanAutoRows, fWidgetHeight - fSpanSize);
      }
    }
  }
  FX_FLOAT fAutoHeigt = 0;
  int32_t iAutoRows = autoRows.GetSize();
  for (int32_t m = 0; m < iAutoRows; m++) {
    fAutoHeigt += static_cast<CFWL_GridColRow*>(autoRows[m])->m_fActualSize;
  }
  FX_FLOAT fScaledHeight = 0;
  iRows = scaledRows.GetSize();
  for (int32_t n = 0; n < iRows; n++) {
    fScaledHeight +=
        static_cast<CFWL_GridColRow*>(scaledRows[n])->m_fActualSize;
  }
  return fFixedHeight + fAutoHeigt + fScaledHeight;
}
FX_BOOL CFWL_GridImp::SetColRowActualSize(CFWL_GridColRow* pColRow,
                                          FX_FLOAT fSize,
                                          FX_BOOL bSetBeyond) {
  if (pColRow->m_MinSize.eUnit == FWL_GRIDUNIT_Fixed &&
      fSize < pColRow->m_MinSize.fLength) {
    pColRow->m_fActualSize = pColRow->m_MinSize.fLength;
    return FALSE;
  }
  if (pColRow->m_MaxSize.eUnit == FWL_GRIDUNIT_Fixed &&
      fSize > pColRow->m_MaxSize.fLength) {
    pColRow->m_fActualSize = pColRow->m_MaxSize.fLength;
    return FALSE;
  }
  if (bSetBeyond) {
    return TRUE;
  }
  pColRow->m_fActualSize = fSize;
  return TRUE;
}
FX_FLOAT CFWL_GridImp::SetWidgetActualWidth(CFWL_GridWidgetInfo* pInfo,
                                            FX_FLOAT fWidth) {
  if (pInfo->m_Size[FWL_GRIDSIZE_MinWidth].eUnit == FWL_GRIDUNIT_Fixed &&
      fWidth < pInfo->m_Size[FWL_GRIDSIZE_MinWidth].fLength) {
    fWidth = pInfo->m_Size[FWL_GRIDSIZE_MinWidth].fLength;
  }
  if (pInfo->m_Size[FWL_GRIDSIZE_MaxWidth].eUnit == FWL_GRIDUNIT_Fixed &&
      fWidth > pInfo->m_Size[FWL_GRIDSIZE_MaxWidth].fLength) {
    fWidth = pInfo->m_Size[FWL_GRIDSIZE_MaxWidth].fLength;
  }
  pInfo->m_fActualWidth = fWidth;
  return fWidth;
}
FX_FLOAT CFWL_GridImp::SetWidgetActualHeight(CFWL_GridWidgetInfo* pInfo,
                                             FX_FLOAT fHeight) {
  if (pInfo->m_Size[FWL_GRIDSIZE_MinHeight].eUnit == FWL_GRIDUNIT_Fixed &&
      fHeight < pInfo->m_Size[FWL_GRIDSIZE_MinHeight].fLength) {
    fHeight = pInfo->m_Size[FWL_GRIDSIZE_MinHeight].fLength;
  }
  if (pInfo->m_Size[FWL_GRIDSIZE_MaxHeight].eUnit == FWL_GRIDUNIT_Fixed &&
      fHeight > pInfo->m_Size[FWL_GRIDSIZE_MaxHeight].fLength) {
    fHeight = pInfo->m_Size[FWL_GRIDSIZE_MaxHeight].fLength;
  }
  pInfo->m_fActualHeight = fHeight;
  return fHeight;
}
void CFWL_GridImp::SetAllWidgetsRect() {
  FX_FLOAT fStartLeft = 0;
  int32_t iColumns = m_Columns.GetSize();
  for (int32_t i = 0; i < iColumns; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Columns[i]);
    if (!pColRow) {
      continue;
    }
    pColRow->m_fActualPos = fStartLeft;
    fStartLeft += pColRow->m_fActualSize;
  }
  FX_FLOAT fStartTop = 0;
  int32_t iRows = m_Rows.GetSize();
  for (int32_t j = 0; j < iRows; j++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(m_Rows[j]);
    if (!pColRow) {
      continue;
    }
    pColRow->m_fActualPos = fStartTop;
    fStartTop += pColRow->m_fActualSize;
  }
  FX_POSITION ps = m_mapWidgetInfo.GetStartPosition();
  while (ps) {
    IFWL_Widget* pWidget = NULL;
    CFWL_GridWidgetInfo* pInfo = NULL;
    m_mapWidgetInfo.GetNextAssoc(ps, (void*&)pWidget, (void*&)pInfo);
    if (!pWidget || !pInfo) {
      continue;
    }
    FX_FLOAT fColumnStart = 0;
    CFWL_GridColRow* pColumn =
        reinterpret_cast<CFWL_GridColRow*>(GetColRow(TRUE, pInfo->m_iColumn));
    if (pColumn) {
      fColumnStart = pColumn->m_fActualPos;
    }
    FX_FLOAT fRowStart = 0;
    CFWL_GridColRow* pRow =
        reinterpret_cast<CFWL_GridColRow*>(GetColRow(FALSE, pInfo->m_iRow));
    if (pRow) {
      fRowStart = pRow->m_fActualPos;
    }
    FX_FLOAT fColumnWidth = 0;
    if (iColumns > 0) {
      for (int32_t j = 0; j < pInfo->m_iColumnSpan; j++) {
        CFWL_GridColRow* pCol = reinterpret_cast<CFWL_GridColRow*>(
            GetColRow(TRUE, pInfo->m_iColumn + j));
        if (!pCol) {
          break;
        }
        fColumnWidth += pCol->m_fActualSize;
      }
    } else {
      fColumnWidth = m_pProperties->m_rtWidget.width;
    }
    FX_FLOAT fRowHeight = 0;
    if (iRows > 0) {
      for (int32_t k = 0; k < pInfo->m_iRowSpan; k++) {
        CFWL_GridColRow* pR = reinterpret_cast<CFWL_GridColRow*>(
            GetColRow(FALSE, pInfo->m_iRow + k));
        if (!pR) {
          break;
        }
        fRowHeight += pR->m_fActualSize;
      }
    } else {
      fRowHeight = m_pProperties->m_rtWidget.height;
    }
    FX_FLOAT fLeftMargin = 0, fRightMargin = 0;
    FX_BOOL bLeftMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Left, fLeftMargin);
    FX_BOOL bRightMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Right, fRightMargin);
    FX_FLOAT fTopMargin = 0, fBottomMargin = 0;
    FX_BOOL bTopMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Top, fTopMargin);
    FX_BOOL bBottomMargin =
        GetWidgetMargin(pWidget, FWL_GRIDMARGIN_Bottom, fBottomMargin);
    if (pInfo->m_Size[FWL_GRIDSIZE_Width].eUnit == FWL_GRIDUNIT_Fixed) {
      SetWidgetActualWidth(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Width].fLength);
    } else {
      if (bLeftMargin && bRightMargin) {
        SetWidgetActualWidth(pInfo, fColumnWidth - fLeftMargin - fRightMargin);
      } else {
        CFX_RectF rtAuto;
        pWidget->GetWidgetRect(rtAuto, TRUE);
        SetWidgetActualWidth(pInfo, rtAuto.width);
      }
    }
    if (pInfo->m_Size[FWL_GRIDSIZE_Height].eUnit == FWL_GRIDUNIT_Fixed) {
      SetWidgetActualHeight(pInfo, pInfo->m_Size[FWL_GRIDSIZE_Height].fLength);
    } else {
      if (bTopMargin && bBottomMargin) {
        SetWidgetActualHeight(pInfo, fRowHeight - fTopMargin - fBottomMargin);
      } else {
        CFX_RectF rtAuto;
        pWidget->GetWidgetRect(rtAuto, TRUE);
        SetWidgetActualHeight(pInfo, rtAuto.height);
      }
    }
    if (bLeftMargin && bRightMargin &&
        pInfo->m_Size[FWL_GRIDSIZE_Width].eUnit == FWL_GRIDUNIT_Fixed) {
      fLeftMargin =
          fColumnStart + fLeftMargin +
          (fColumnWidth - fLeftMargin - fRightMargin - pInfo->m_fActualWidth) /
              2;
    } else if (bLeftMargin) {
      fLeftMargin = fColumnStart + fLeftMargin;
    } else if (bRightMargin) {
      fLeftMargin =
          fColumnStart + fColumnWidth - fRightMargin - pInfo->m_fActualWidth;
    } else {
      fLeftMargin = fColumnStart;
    }
    if (bTopMargin && bBottomMargin &&
        pInfo->m_Size[FWL_GRIDSIZE_Height].eUnit == FWL_GRIDUNIT_Fixed) {
      fTopMargin =
          fRowStart + fTopMargin +
          (fRowHeight - fTopMargin - fBottomMargin - pInfo->m_fActualHeight) /
              2;
    } else if (bTopMargin) {
      fTopMargin = fRowStart + fTopMargin;
    } else if (bBottomMargin) {
      fTopMargin =
          fRowStart + fRowHeight - fBottomMargin - pInfo->m_fActualHeight;
    } else {
      fTopMargin = fRowStart;
    }
    CFX_RectF rtWidget, rtOld;
    rtWidget.Set(fLeftMargin, fTopMargin, pInfo->m_fActualWidth,
                 pInfo->m_fActualHeight);
    pWidget->GetWidgetRect(rtOld);
    if (rtWidget == rtOld) {
      continue;
    }
    pWidget->SetWidgetRect(rtWidget);
    if (rtWidget.width == rtOld.width && rtWidget.height == rtOld.height) {
      continue;
    }
    pWidget->Update();
  }
}
FX_BOOL CFWL_GridImp::IsGrid(IFWL_Widget* pWidget) {
  if (!pWidget)
    return FALSE;
  return pWidget->GetClassID() == FWL_CLASSHASH_Grid;
}
void CFWL_GridImp::SetSpanAutoColRowSize(const CFX_PtrArray& spanAutos,
                                         FX_FLOAT fTotalSize) {
  int32_t iAutoColRows = spanAutos.GetSize();
  if (iAutoColRows < 1) {
    return;
  }
  CFX_PtrArray autoNoMinMaxs;
  FX_FLOAT fAutoPer = fTotalSize / iAutoColRows;
  for (int32_t j = 0; j < iAutoColRows; j++) {
    CFWL_GridColRow* pColumn = static_cast<CFWL_GridColRow*>(spanAutos[j]);
    FX_FLOAT fOrgSize = pColumn->m_fActualSize;
    if (SetColRowActualSize(pColumn, pColumn->m_fActualSize + fAutoPer, TRUE)) {
      autoNoMinMaxs.Add(pColumn);
    } else {
      fTotalSize -= pColumn->m_fActualSize - fOrgSize;
      int32_t iNoMinMax = iAutoColRows - (j + 1 - autoNoMinMaxs.GetSize());
      if (iNoMinMax > 0 && fTotalSize > 0) {
        fAutoPer = fTotalSize / iNoMinMax;
      } else {
        break;
      }
    }
  }
  int32_t iNormals = autoNoMinMaxs.GetSize();
  if (fTotalSize > 0) {
    if (iNormals == iAutoColRows) {
      fAutoPer = fTotalSize / iNormals;
      for (int32_t k = 0; k < iNormals; k++) {
        CFWL_GridColRow* pColumn =
            static_cast<CFWL_GridColRow*>(autoNoMinMaxs[k]);
        pColumn->m_fActualSize += fAutoPer;
      }
    } else {
      SetSpanAutoColRowSize(autoNoMinMaxs, fTotalSize);
    }
  } else {
  }
}
void CFWL_GridImp::SetSpanScaledColRowSize(const CFX_PtrArray& spanScaleds,
                                           FX_FLOAT fTotalSize,
                                           FX_FLOAT fTotalScaledNum) {
  int32_t iScaledColRows = spanScaleds.GetSize();
  if (iScaledColRows < 1) {
    return;
  }
  CFX_PtrArray autoNoMinMaxs;
  FX_FLOAT fPerSize = fTotalSize / fTotalScaledNum;
  for (int32_t i = 0; i < iScaledColRows; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(spanScaleds[i]);
    if (SetColRowActualSize(pColRow, pColRow->m_fActualSize +
                                         fPerSize * pColRow->m_Size.fLength,
                            TRUE)) {
      autoNoMinMaxs.Add(pColRow);
    } else {
      fTotalSize -= pColRow->m_fActualSize;
      fTotalScaledNum -= pColRow->m_Size.fLength;
      int32_t iNoMinMax = iScaledColRows - (i + 1 - autoNoMinMaxs.GetSize());
      if (iNoMinMax > 0 && fTotalSize > 0) {
        fPerSize = fTotalSize / fTotalScaledNum;
      } else {
        break;
      }
    }
  }
  int32_t iNormals = autoNoMinMaxs.GetSize();
  if (fTotalSize > 0) {
    if (iNormals == iScaledColRows) {
      fPerSize = fTotalSize / fTotalScaledNum;
      for (int32_t j = 0; j < iNormals; j++) {
        CFWL_GridColRow* pColumn =
            static_cast<CFWL_GridColRow*>(autoNoMinMaxs[j]);
        pColumn->m_fActualSize += fPerSize * pColumn->m_Size.fLength;
      }
    } else {
      SetSpanScaledColRowSize(autoNoMinMaxs, fTotalSize, fTotalScaledNum);
    }
  } else {
  }
}
void CFWL_GridImp::SetScaledColRowsSize(const CFX_PtrArray& spanScaleds,
                                        FX_FLOAT fTotalSize,
                                        FX_FLOAT fTotalScaledNum) {
  int32_t iScaledColRows = spanScaleds.GetSize();
  if (iScaledColRows < 1) {
    return;
  }
  CFX_PtrArray autoNoMinMaxs;
  FX_FLOAT fPerSize = fTotalSize / fTotalScaledNum;
  for (int32_t i = 0; i < iScaledColRows; i++) {
    CFWL_GridColRow* pColRow = static_cast<CFWL_GridColRow*>(spanScaleds[i]);
    if (!pColRow) {
      continue;
    }
    FX_FLOAT fSize = fPerSize * pColRow->m_Size.fLength;
    FX_FLOAT fOrgSize = pColRow->m_fActualSize;
    if (SetColRowActualSize(pColRow, fSize, TRUE)) {
      autoNoMinMaxs.Add(pColRow);
    } else {
      fTotalSize -= pColRow->m_fActualSize - fOrgSize;
      fTotalScaledNum -= pColRow->m_Size.fLength;
      int32_t iNoMinMax = iScaledColRows - (i + 1 - autoNoMinMaxs.GetSize());
      if (iNoMinMax > 0 && fTotalSize > 0) {
        fPerSize = fTotalSize / fTotalScaledNum;
      } else {
        break;
      }
    }
  }
  int32_t iNormals = autoNoMinMaxs.GetSize();
  if (fTotalSize > 0) {
    if (iNormals == iScaledColRows) {
      fPerSize = fTotalSize / fTotalScaledNum;
      for (int32_t i = 0; i < iNormals; i++) {
        CFWL_GridColRow* pColRow =
            static_cast<CFWL_GridColRow*>(autoNoMinMaxs[i]);
        if (!pColRow) {
          continue;
        }
        FX_FLOAT fSize = fPerSize * pColRow->m_Size.fLength;
        pColRow->m_fActualSize = fSize;
      }
    } else {
      SetScaledColRowsSize(autoNoMinMaxs, fTotalSize, fTotalScaledNum);
    }
  } else {
  }
}
CFWL_GridImpDelegate::CFWL_GridImpDelegate(CFWL_GridImp* pOwner)
    : m_pOwner(pOwner) {}
int32_t CFWL_GridImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
  if (pMessage->GetClassID() != FWL_MSGHASH_Mouse) {
    return 0;
  }
  CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
  if (pMsg->m_dwCmd != FWL_MSGMOUSECMD_LButtonDown) {
    return 0;
  }
  return 1;
}
FWL_ERR CFWL_GridImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
                                           const CFX_Matrix* pMatrix) {
  return m_pOwner->DrawWidget(pGraphics, pMatrix);
}