//----------------------------------------------------------------------------//
// ObjectWindows, Copyright (c) 1998 by Yura Bidus.                           //
//                                                                            //
// THIS CLASS AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF         //
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO        //
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A             //
// PARTICULAR PURPOSE.                                                        //
//                                                                            //
// Implementation of class TPickerCell, TColorCell, TBitmapCell, TTextCell,   //
//                         TGridPicker, TColorPicker and TColorPickerGadget   //
//------------------------------------------------------------------------------
#include <owl/pch.h>
 
#include <owl/uihelper.h>
#include <owl/celarray.h>
#include <owl/tooltip.h>
#include <owl/gadgetwi.h>
#include <owl/chooseco.h>
#include <owl/uimetric.h>
#include <owl/picker.h>
#include <owl/template.h>
#include <owl/decframe.h>
#if defined(BI_MULTI_THREAD_RTL)
#include <owl/thread.h>
#endif
 
#include <algorithm>
 
#define ID_STATITEM    0
#define ID_CUSTITEM    1
#define ID_DEFITEM    2
#define ID_DELTA      3
#define ID_MINITEM    2
 
namespace owl {
 
OWL_DIAGINFO;
 
//------------------------------------------------------------------------------
//
// class TPickerCellArray
// ~~~~~ ~~~~~~~~~~~~~~~~
//
class TPickerCellArray: public TIPtrArray<TPickerCell*>{
  public:
    TPickerCellArray(){}
};
 
//------------------------------------------------------------------------------
//
// class TDefTextCell
// ~~~~~ ~~~~~~~~~~~~
//
class TDefTextCell: public TTextCell {
  public:
    TDefTextCell(int id=0, LPCTSTR text=_T(""),TPickerCell* cell=0);
    virtual  ~TDefTextCell();
 
    virtual void   PaintCell(TDC& dc, TRect& rect);
    void            SetCell(TPickerCell* cell) {  delete Cell; Cell = cell; }
    TPickerCell*   GetCell()                  { return Cell;               }
 
  protected:
    TPickerCell*   Cell;
};
//------------------------------------------------------------------------------
// class TLocalTipCell
// ~~~~~ ~~~~~~~~~~~~~
//
class TLocalTipCell: public TTextCell {
  public:
    TLocalTipCell(int id=0, LPCTSTR text=_T(""));
 
    virtual void   PaintCell(TDC& dc, TRect& rect);
};
//------------------------------------------------------------------------------
 
 
//------------------------------------------------------------------------------
//
// class TPickerCell
// ~~~~~~~~~~~~~~~~~
//
//
// Set the border style used by this gadget. Internal Border members are
// updated and owning Window is notified of a size change.
//
void
TPickerCell::SetBorderStyle(TBorderStyle borderStyle)
{
  BorderStyle = borderStyle;
  if (Parent)
    Parent->Layout();
}
 
//
void
TPickerCell::Paint(TDC& dc, TRect* r, bool drawbrd)
{
  TRect rect(r ? *r : TRect(TPoint(0,0),Bounds.Size()));
 
  if(!Parent->IsFlatStyle())
    rect.Inflate(-1,-1);
 
  if(drawbrd)
    PaintBorder(dc, rect);
 
  if(!Parent->IsFlatStyle())
    PaintCell(dc, rect.Inflate(-2,-2));
  else
    PaintCell(dc, rect.Inflate(-4,-4));
}
 
//
void
TPickerCell::PaintBorder(TDC& dc, TRect& rect)
{
  if (BorderStyle == None)
    return;
 
  if(BorderStyle == Flat){
    if(!Parent->IsFlatStyle()){
      uint flag  = TUIBorder::Soft|TUIBorder::Rect;
      uint style = TUIBorder::WndRecessed;
 
      if(IsSet(csMouseIn))
        style  = TUIBorder::Embossed;
      if(IsSet(csSelected))
        flag |= TUIBorder::Mono;
 
      TUIBorder(rect, TUIBorder::TStyle(style),TUIBorder::TFlag(flag)).Paint(dc);
    }
    else{
      if(IsSet(csSelected)){
        TUIBorder(rect, TUIBorder::Recessed).Paint(dc);
        if(!IsSet(csMouseIn)){
#if 1   //  Y.B. Excell Style
          dc.FillRect(rect.InflatedBy(-1, -1), TUIFace::GetDitherBrush());
#else   // Y.B. Dieter Windau style. What better ??????
          dc.FillRect(rect.InflatedBy(-2, -2), TUIFace::GetDitherBrush());
#endif
        }
      }
      else if(IsSet(csMouseIn))
        TUIBorder(rect, TUIBorder::RaisedInner, TUIBorder::Adjust|TUIBorder::Rect).Paint(dc);
      else{
        TBrush br(TColor::Sys3dFace);
        dc.FrameRect(rect, br);
      }
      TBrush shbr(TColor::Sys3dShadow);
      dc.FrameRect(rect.InflatedBy(-3, -3), shbr);
    }
  }
  else{
    if (BorderStyle == Plain) {
      TBrush winBru(TColor::SysWindowFrame);
      dc.OWLFastWindowFrame(winBru, rect,TUIMetric::CxBorder, TUIMetric::CyBorder);
      dc.RestoreBrush();
    }
    else
      TUIBorder(rect, TUIBorder::TStyle(BorderStyle)).Paint(dc);
  }
}
 
//
void
TPickerCell::QueryBounds(TRect& rect)
{
   TSize size = TSize(13,13);
  if(rect.Width() < size.cx)
    rect.right = rect.left + size.cx;
  if(rect.Height() < size.cy)
    rect.bottom = rect.top + size.cy;
}
 
//
void
TPickerCell::EnterMouse()
{
  Set(csMouseIn);
}
 
//
void
TPickerCell::LeaveMouse()
{
  Clear(csMouseIn);
}
 
//
void
TPickerCell::Select(bool sel)
{
  if(sel)
    Set(csSelected);
  else
    Clear(csSelected);
}
 
//------------------------------------------------------------------------------
// class TColorCell
// ~~~~~ ~~~~~~~~~~
//
void
TColorCell::PaintCell(TDC& dc, TRect& rect)
{
  TColor clr2 = dc.SetBkColor(Color);
  dc.TextRect(rect);
  dc.SetBkColor(clr2);
}
 
//------------------------------------------------------------------------------
// class TBitmapCell
// ~~~~~ ~~~~~~~~~~~
TBitmapCell::TBitmapCell(int id, TCelArray* array, int index,TBorderStyle style)
:
  TPickerCell(id,style),
  CelArray(array),
  Index(index),
  ShouldDelete(false)
{
}
 
//
TBitmapCell::~TBitmapCell()
{
  if(ShouldDelete)
    delete CelArray;
}
 
//
void
TBitmapCell::SetCelArray(TCelArray* array, TAutoDelete del)
{
  if(ShouldDelete)
    delete CelArray;
  CelArray = array;
  ShouldDelete = del==AutoDelete;
}
 
//
void
TBitmapCell::PaintCell(TDC& dc, TRect& rect)
{
  if(CelArray){
    if(rect.Size() == CelArray->CelSize())
      CelArray->BitBlt(Index, dc, rect.left, rect.top);
    else
      CelArray->StretchBlt(Index, dc, rect);
  }
}
 
//
void
TBitmapCell::QueryBounds(TRect& rect)
{
  TSize size;
  if(CelArray){
    if(Parent->IsFlatStyle())
     size = CelArray->CelSize()+TSize(8,8);
    else
     size = CelArray->CelSize()+TSize(6,6);
  }
  else{
    if(Parent->IsFlatStyle())
      size = TSize(13,13);
    else
      size = TSize(9,9);
  }
  if(rect.Width() < size.cx)
    rect.right = rect.left + size.cx;
  if(rect.Height() < size.cy)
    rect.bottom = rect.top + size.cy;
}
//------------------------------------------------------------------------------
//
// class TTextCell
// ~~~~~ ~~~~~~~~~
void
TTextCell::PaintCell(TDC& dc, TRect& rect)
{
  if(!Parent->IsFlatStyle())
    rect.Inflate(-1, -1);
 
  TFont* font = Parent->GetFont();
  if(font){
    CHECK(font->IsGDIObject());
    dc.SelectObject(*font);
  }
 
  int mode = dc.SetBkMode(TRANSPARENT);
  tstring tmp (Text);
  dc.DrawTextEx(&tmp[0], -1, &rect, Format);
  dc.SetBkMode(mode);
 
  if(font)
    dc.RestoreFont();
}
//------------------------------------------------------------------------------
//
// class TDefTextCell
// ~~~~~ ~~~~~~~~~~~~
//
//
TDefTextCell::TDefTextCell(int id, LPCTSTR text,TPickerCell* cell)
:
  TTextCell(id,text),
  Cell(cell)
{
}
 
//
TDefTextCell::~TDefTextCell()
{
  delete Cell;
}
 
//
void
TDefTextCell::PaintCell(TDC& dc, TRect& rect)
{
  if(!Parent->IsFlatStyle())
    rect.Inflate(-1, -1);
 
  if(Cell){
    int width = Bounds.Height()-6;
    TRect rc(rect.left-2, rect.top-2, rect.left+width, rect.top+width);
    if(!Parent->IsFlatStyle())
      rc.Inflate(1, 1);
    Cell->Paint(dc, &rc, false);
    if(Parent->IsFlatStyle())
      dc.FrameRect(rc.InflatedBy(-3,-3), TBrush(TColor::Sys3dShadow));
    rect.left += rc.Width()-5;
  }
   rect.Inflate(1,1);
  TTextCell::PaintCell(dc, rect);
}
 
//------------------------------------------------------------------------------
// class TLocalTipCell
// ~~~~~ ~~~~~~~~~~~~~
//
TLocalTipCell::TLocalTipCell(int id, LPCTSTR text)
:
  TTextCell(id,text, None)
{
  Format = DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS|DT_NOCLIP;
}
 
//
void
TLocalTipCell::PaintCell(TDC& dc, TRect&)
{
  TRect rect(TPoint(0,0),Bounds.Size());
  rect.Inflate(-2,-2);
 
  TColor clr;
  if(!Parent->IsFlatStyle())
    clr = dc.SetBkColor(TColor::White);
 
  dc.TextRect(rect);
 
  if(!Parent->IsFlatStyle())
    dc.SetBkColor(clr);
 
  TTextCell::PaintCell(dc, rect);
 
  TUIBorder(rect.InflatedBy(2,2), Parent->IsFlatStyle()?TUIBorder::Recessed:
            TUIBorder::WndRecessed).Paint(dc);
}
//------------------------------------------------------------------------------
//
// Response Table
//
DEFINE_RESPONSE_TABLE1(TGridPicker, TControl)
  //EV_WM_ACTIVATEAPP,
  EV_WM_SETFOCUS,
  EV_WM_KILLFOCUS,
  //EV_WM_GETDLGCODE,
  EV_WM_LBUTTONDOWN,
  EV_WM_LBUTTONDBLCLK,
  EV_WM_LBUTTONUP,
  EV_WM_MOUSEMOVE,
  EV_WM_KEYDOWN,
  EV_WM_KEYUP,
  EV_WM_CANCELMODE,
END_RESPONSE_TABLE;
 
TGridPicker::TGridPicker(TWindow* parent, int id, int x, int y, int w, int h,
                           TModule* module)
:
  TControl(parent, id, 0, x, y, w, h, module)
{
  InitPicker();
}
 
//
TGridPicker::TGridPicker(TWindow* parent, int resourceId, TModule* module)
:
  TControl(parent, resourceId, module)
{
  InitPicker();
}
 
//
void
TGridPicker::InitPicker()
{
  Selected     = -1;
  Focused     = -1;
  NRows        = 0;
  NColumns    = 4;
//  TextHeight  = 0;
  Margins     = TMargins(TMargins::Pixels, 4, 4, 4, 4);
  Font        = 0;
  Target      = 0;
  Tooltip      = 0;
  Cells       = new  TPickerCellArray;
 
 
  ModifyExStyle(0,WS_EX_WINDOWEDGE);
 
  SetBkgndColor(TColor::Sys3dFace);
 
  // Create the font
  NONCLIENTMETRICS ncm;
  ncm.cbSize = sizeof(NONCLIENTMETRICS);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
  Font = new TFont(ncm.lfMessageFont);
 
  TEXTMETRIC  metrics;
  Font->GetTextMetrics(metrics);
  TextHeight = std::max(metrics.tmHeight + metrics.tmExternalLeading, 20l);
 
 
  Add(new TLocalTipCell(ID_STATITEM));  // == 0
  Add(new TDefTextCell(ID_CUSTITEM));   // == 1
  Add(new TDefTextCell(ID_DEFITEM));    // == 2
}
 
TGridPicker::~TGridPicker()
{
  delete Font;
  delete Cells;
}
 
//
void
TGridPicker::SetSelection(int loc)
{
  loc += ID_DELTA;
  if(loc >= (int)Cells->Size() || loc < ID_MINITEM){
    if(loc == ID_CUSTITEM){
      Set(ppButtonSel);
      (*Cells)[ID_CUSTITEM]->Select(true);
      if(GetHandle())
        InvalidateRect((*Cells)[ID_CUSTITEM]->Bounds,true);
    }
    return;
  }
  if(IsSet(ppButtonSel)){
    Clear(ppButtonSel);
    (*Cells)[ID_CUSTITEM]->Select(false);
    if(GetHandle())
      InvalidateRect((*Cells)[ID_CUSTITEM]->Bounds,true);
  }
 
  if(Selected >= 0){
    (*Cells)[Selected]->Select(false);
    if(GetHandle())
      InvalidateRect((*Cells)[Selected]->Bounds,true);
  }
  Selected   = loc;
  (*Cells)[Selected]->Select(true);
  if(GetHandle()){
    InvalidateRect((*Cells)[Selected]->Bounds,true);
  }
}
//
void
TGridPicker::ApplyChanges()
{
  if(GetHandle()){
    Layout();
    Invalidate();
  }
}
 
//
void
TGridPicker::SetColumns(int colmn)
{
  NColumns  = colmn;
  NRows  = (Cells->Size()-ID_DELTA)/NColumns;
  if((Cells->Size()-ID_DELTA)%NColumns)
    NRows++;
 
  ApplyChanges();
}
 
//
void
TGridPicker::SetMargins(const TMargins& margins)
{
  Margins = margins;
  ApplyChanges();
}
 
//
void
TGridPicker::SetFont(const TFont& font)
{
  delete Font;
  Font  = new TFont(font);
}
 
//
void
TGridPicker::EnableDefault(LPCTSTR text, int resId, TPickerCell* cl)
{
  TDefTextCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_DEFITEM], TDefTextCell);
  if(text){
    Set(ppShowDefItem);
    if(cell){
      cell->SetText(text);
      cell->SetId(resId);
      if(cl)
        cl->Parent  = this;
      cell->SetCell(cl);
    }
  }
  else{
    Clear(ppShowDefItem);
    if(cell)
      cell->Bounds = {};
  }
 
  ApplyChanges();
}
 
//
void
TGridPicker::EnableButton(LPCTSTR text, int resId, TPickerCell* cl)
{
  TDefTextCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_CUSTITEM], TDefTextCell);
  if(text){
    Set(ppShowCustItem);
    if(cell){
      cell->SetText(text);
      cell->SetId(resId);
      if(cl)
        cl->Parent  = this;
      cell->SetCell(cl);
    }
  }
  else{
    Clear(ppShowCustItem);
    if(cell)
      cell->Bounds = {};
  }
 
  ApplyChanges();
}
 
//
void
TGridPicker::ModifyPopStyle(uint off, uint on)
{
  if(on)
    Set(on);
  if(off)
    Clear(off);
 
  if(off & psLocalTips){
    TLocalTipCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_STATITEM], TLocalTipCell);
    if(cell)
      cell->Bounds = {};
  }
  ApplyChanges();
}
 
//
int
TGridPicker::Add(TPickerCell* cell)
{
  cell->Parent = this;
  return Cells->Add(cell);
}
 
//
TPickerCell*
TGridPicker::Remove(int loc)
{
  if(loc >= (int)Cells->Size())
    return 0;
 
  TPickerCell* cell = (*Cells)[loc];
  Cells->Detach(loc);
 
  return cell;
}
 
//
TPickerCell*
TGridPicker::GetCell(int loc)
{
  if(loc < (int)Cells->Size())
    return (*Cells)[loc];
  return 0;
}
 
//
uint
TGridPicker::Size()
{
  return Cells->Size();
}
 
//
void
TGridPicker::AddCell(TPickerCell* cell, bool select)
{
  int idx = Add(cell);
  if(select)
    SetSelection(idx-ID_DELTA);
  SetColumns(NColumns);
}
 
//
TPickerCell*
TGridPicker::RemoveCell(int loc)
{
  loc += ID_DELTA;
  return Remove(loc);
}
 
//
TPickerCell*
TGridPicker::GetDefaultCell()
{
  TDefTextCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_DEFITEM], TDefTextCell);
  if(!cell)
    return 0;
  return cell->GetCell();
}
 
//
// return child of default custom cell
//
TPickerCell*
TGridPicker::GetCustomCell()
{
  TDefTextCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_CUSTITEM], TDefTextCell);
  if(!cell)
    return 0;
  return cell->GetCell();
}
 
//
auto TGridPicker::GetWindowClassName() -> TWindowClassName
{
  return TWindowClassName{OWL_PICKER};
}
 
//
void
TGridPicker::GetWindowClass(WNDCLASS& wndClass)
{
  TControl::GetWindowClass(wndClass);
  wndClass.style = CS_HREDRAW|CS_VREDRAW|CS_PARENTDC;
}
 
//
void
TGridPicker::SetupWindow()
{
  TControl::SetupWindow();
 
  Layout();
 
  if (Tooltip && !Tooltip->GetHandle()){
    // Make sure tooltip is disabled so it does not take input focus
    Tooltip->ModifyStyle(0,WS_DISABLED);
    Tooltip->Create();
  }
 
  if (Tooltip)
  {
    for (int i = 0; i != static_cast<int>(Cells->Size()); ++i)
    {
      auto& c = *(*Cells)[i];
      if (const auto id = c.GetId())
        Tooltip->AddTool({GetHandle(), static_cast<uint>(id)}, c.GetBounds(), LoadTipText(id));
    }
  }
}
//
void
TGridPicker::EnableTooltip(bool enable)
{
  if (!Tooltip) {
    // Create and initialize tooltip
    //
    SetTooltip(new TTooltip(this));
  }
  else {
    if (Tooltip->GetHandle())
      Tooltip->Activate(enable);
  }
}
//
void
TGridPicker::SetTooltip(TTooltip* tooltip)
{
  // Cleanup; via Condemned list if tooltip was created
  //
  if (Tooltip) {
    if (Tooltip->GetHandle())
      Tooltip->SendMessage(WM_CLOSE);
    else
      delete Tooltip;
  }
 
  // Store new tooltip and create if necessary
  //
  Tooltip = tooltip;
  if (Tooltip) {
    if(GetHandle() && !Tooltip->GetHandle()) {
      // Make sure tooltip is disabled so it does not take input focus
      Tooltip->ModifyStyle(0,WS_DISABLED);
      Tooltip->Create();
    }
  }
}
 
//
// Relay 'interesting' messages to the tooltip window
//
bool
TGridPicker::PreProcessMsg(MSG& msg)
{
  // Check if this message might be worth relaying to the tooltip window
  //
  if (Tooltip && Tooltip->IsWindow()) {
    if (msg.hwnd == *this || IsChild(msg.hwnd)) {
      if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) {
        Tooltip->RelayEvent(msg);
      }
    }
  }
 
  // Always let event go through.
  //
  return TControl::PreProcessMsg(msg);
}
 
//
//
const int CellSpacing = 2;
 
//
void
TGridPicker::Layout()
{
  if(!GetHandle())
    return;
 
  TRect rect;
  GetClientRect(rect);
 
  // 1. Check Max size
  TRect crect;
  GetCellRect(crect);
  if(crect.IsEmpty())
    crect = TRect(TPoint(0,0),TSize(rect.Width()/NColumns,rect.Height()/NRows));
 
  TSize size(crect.Width()*NColumns,crect.Height()*NRows);
  int addHeight = 0;
  if(IsSet(ppShowDefItem))
    addHeight += TextHeight+CellSpacing;
  if(IsSet(ppShowCustItem))
    addHeight += TextHeight+CellSpacing*3;
  if(IsSet(ppShowTipsCell))
    addHeight += TextHeight+CellSpacing*3;
 
  size.cy += addHeight;
 
  int leftM, rightM, topM, bottomM;
  Margins.GetPixels(leftM, rightM, topM, bottomM, TextHeight);
  crect = TRect(TPoint(0,0),TSize(size.cx+leftM+rightM,size.cy+topM+bottomM));
 
  bool move = false;
  if(crect.Width() > rect.Width()){
    rect.right = rect.left + crect.Width();
    move = true;
  }
  if(crect.Height() > rect.Height()){
    rect.bottom = rect.top + crect.Height();
    move = true;
  }
 
  // 2. Reposition Window
  if(move)
    SetWindowPos(HWND_TOPMOST, rect, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
 
  int w = (rect.Width()-leftM-rightM )/NColumns;
  int h = (rect.Height()-addHeight-topM-bottomM)/NRows;
 
  // 3. Find max rectangle
  TRect cellRect;
  if(IsSet(ppShrCells))
    GetCellRect(cellRect);
  if(cellRect.IsEmpty())
    cellRect = TRect(0,0, w,h);
   cellRect.Offset(leftM,topM);
 
  addHeight = 0;
  if(IsSet(ppShowDefItem)){
    (*Cells)[ID_DEFITEM]->Bounds =
                       TRect(TPoint(leftM,topM),
                             TSize(rect.Width()-leftM-rightM,TextHeight));
    cellRect.Offset(0,TextHeight+CellSpacing);
    addHeight +=TextHeight+CellSpacing;
  }
 
  if(IsSet(ppShowCustItem)){
    addHeight += CellSpacing*3;
    (*Cells)[ID_CUSTITEM]->Bounds =
                        TRect(TPoint(leftM,h*NRows+topM+addHeight),
                              TSize(rect.Width()-leftM-rightM,TextHeight));
    addHeight +=TextHeight;
  }
 
  if(IsSet(ppShowTipsCell)){
    addHeight += CellSpacing*3;
    (*Cells)[ID_STATITEM]->Bounds =
                        TRect(TPoint(leftM,h*NRows+topM+addHeight),
                              TSize(rect.Width()-leftM-rightM,TextHeight));
  }
 
  // 4. Layout Cells
  rect = cellRect;
  for(int i = 0; i < NRows; i++){
    for(int j = 0; j < NColumns; j++){
      int cell  =  i*NColumns+j + ID_DELTA;
      if(cell < (int)Cells->Size()){
        (*Cells)[cell]->Bounds = cellRect;
        cellRect.Offset(w,0);
      }
    }
    cellRect = rect.Offset(0,cellRect.Height());
  }
}
 
//
int
TGridPicker::Contains(const TPoint& point)
{
  for(int i = 0; i < (int)Cells->Size(); i++){
    if((*Cells)[i]->PtIn(point))
      return i;
  }
  return Cells->NPOS;
}
 
//
void
TGridPicker::GetCellRect(TRect& cellRect)
{
  for(int i = ID_DELTA; i < (int)Cells->Size(); i++){
    TRect rec;
    (*Cells)[i]->QueryBounds(rec);
    cellRect |= rec;
  }
}
 
//
void
TGridPicker::Paint(TDC& dc, bool /*erase*/, TRect& rect)
{
  TPoint viewport = dc.GetViewportOrg();
  for(int i = 0; i < (int)Cells->Size(); i++){
    if ((*Cells)[i]->GetBounds().Touches(rect)){
      dc.SetViewportOrg((TPoint&)(*Cells)[i]->GetBounds());
      (*Cells)[i]->Paint(dc);
    }
  }
  dc.SetViewportOrg(viewport);
 
  if(IsSet(ppShowCustItem)){
     TRect tr((*Cells)[ID_CUSTITEM]->GetBounds());
     PaintDivider(dc, tr);
  }
 
  if(IsSet(ppShowTipsCell)){
     TRect tr((*Cells)[ID_STATITEM]->GetBounds());
     PaintDivider(dc, tr);
  }
}
 
//
void
TGridPicker::PaintDivider(TDC& dc, const TRect& r)
{
  TRect rect = r;
  if(IsFlatStyle())
    rect.Inflate(-1, -1);
  rect.Offset(0,-(CellSpacing*3)-1);
  rect.top     += CellSpacing;
  rect.bottom = rect.top + CellSpacing;
  TUIBorder(rect, TUIBorder::Recessed, TUIBorder::Adjust|TUIBorder::Rect).Paint(dc);
}
 
//
bool
TGridPicker::CallCustomBox()
{
  return false;
}
 
//
void
TGridPicker::ExitPicker(bool /*status*/)
{
}
 
//
void
TGridPicker::RefocusCell(int loc)
{
  if(Focused >= 0){
    (*Cells)[Focused]->LeaveMouse();
    InvalidateRect((*Cells)[Focused]->Bounds,true);
  }
  Focused = loc;
  (*Cells)[loc]->EnterMouse();
  InvalidateRect((*Cells)[loc]->Bounds,true);
  // set text cell string
  if(IsSet(ppShowTipsCell)){
    TLocalTipCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_STATITEM], TLocalTipCell);
    if(cell && (*Cells)[loc]->GetId()){
      cell->SetText(LoadTipText((*Cells)[loc]->GetId()).c_str());
      InvalidateRect(cell->Bounds,true);
    }
  }
  // Set/reset message box string
  if(IsSet(ppMessageTips)){
    if(loc > 0 && (*Cells)[loc]->GetId())
      SetStatusBarMessage((*Cells)[loc]->GetId());
    else
      SetStatusBarMessage(-1);
  }
  if(GetStyle() & BS_NOTIFY)
    NotifyParent(BN_HILITE);
}
 
//
//
void
TGridPicker::NotifyParent(uint code)
{
  if(Target)
    SendNotification(*Target, GetDlgCtrlID(), code, *this);
  else
    SendNotification(::GetParent(*this), GetDlgCtrlID(), code, *this);
}
 
//
// WM_SETFOCUS handler
//
void
TGridPicker::EvSetFocus(THandle hWndLostFocus)
{
  TControl::EvSetFocus(hWndLostFocus);
 
  Set(ppFocus);
  Invalidate(true);
}
 
//
// WM_KILLFOCUS handler
//
void
TGridPicker::EvKillFocus(THandle hWndGetFocus)
{
  TControl::EvKillFocus(hWndGetFocus);
 
  Clear(ppFocus);
  ClearCell();
  if (IsSet(ppPushed))
    ClearCapture();
}
 
//
// WM_LBUTTONDOWN handler. Grab focus and update button's state to be in
// 'pushed' mode.
//
void
TGridPicker::EvLButtonDown(uint modKeys, const TPoint& point)
{
  TControl::EvLButtonDown(modKeys, point);
 
  SetCapture();
  if(!IsSet(ppFocus))
    SetFocus();
  const auto loc = Contains(point);
  if (loc != Cells->NPOS)
  {
    SetSelection(loc-ID_DELTA);
    Set(ppPushed);
  }
}
 
 
//
// WM_LBUTTONDBLCLK handler. Simply forward to LBUTTONDOWN handler
//
void
TGridPicker::EvLButtonDblClk(uint modKeys, const TPoint& point)
{
  EvLButtonDown(modKeys, point);
}
 
//
// WM_LBUTTONUP handler. Restore state of button and notify parent with a
// CLICKED message if necessary.
//
void
TGridPicker::EvLButtonUp(uint /*modKeys*/, const TPoint& point)
{
  if (GetCapture() == *this) {
    ReleaseCapture();
 
    if(IsSet(ppButtonSel)){
      Clear(ppButtonSel);
      (*Cells)[ID_CUSTITEM]->Select(false);
      InvalidateRect((*Cells)[ID_CUSTITEM]->Bounds,true);
 
      Set(ppCustomOpen);
      if(!CallCustomBox()){
        Clear(ppCustomOpen);
        return;
      }
      Clear(ppCustomOpen);
 
      if(Selected >= 0)
        (*Cells)[Selected]->Select(false);
      Selected = ID_CUSTITEM;
      (*Cells)[ID_CUSTITEM]->Select(true);
 
      NotifyParent(BN_CLICKED);
      ExitPicker(true);
      return;
    }
    TRect rect;
    GetClientRect(rect);
    if (rect.Contains(point) && Contains(point) >= ID_MINITEM){
      NotifyParent(BN_CLICKED);
      ExitPicker(true);
    }
  }
}
 
//
// WM_MOUSEMOVE handler. Update state of button if we're in 'capture' mode.
//
void
TGridPicker::EvMouseMove(uint modKeys, const TPoint& point)
{
  if(IsSet(ppFocus) && IsSet(ppTrackMouse)){
    TRect rect;
    GetClientRect(rect);
 
    int loc;
    if (!rect.Contains(point) || (loc = Contains(point)) == Cells->NPOS)
      ClearCell();
    else if(Focused != loc){
      RefocusCell(loc);
 
       if (modKeys & MK_LBUTTON && GetCapture() == *this)
        SetSelection(loc-ID_DELTA);
    }
  }
}
 
//
// WM_KEYDOWN handler. Update state of button upon detecting that user
// pressed the space bar.
//
void
TGridPicker::EvKeyDown(uint key, uint repeatCount, uint flags)
{
  TControl::EvKeyDown(key, repeatCount, flags);
 
  switch (key){
    case VK_ESCAPE:
      ExitPicker(false);
    break;
 
    case VK_RETURN:
    case VK_SPACE:
      Set(ppPushed);
      if(Focused < 0)
        Focused = 0;
      break;
 
    case VK_LEFT:{
        int loc = Focused-1;
        if(Focused == -1 || Focused == ID_DEFITEM)
          loc = IsSet(ppShowCustItem) ? ID_CUSTITEM : Cells->Size()-1;
        else if(Focused == ID_CUSTITEM)
          loc = Cells->Size()-1;
        else if(loc < ID_DELTA && !IsSet(ppShowDefItem))
          loc = IsSet(ppShowCustItem) ? ID_CUSTITEM : Cells->Size()-1;
        else if( loc < ID_DELTA && IsSet(ppShowDefItem))
          loc = ID_DEFITEM;
        RefocusCell(loc);
      }
      break;
 
    case VK_RIGHT: {
        int loc = Focused+1;
        int maxcell = Cells->Size()-1;
        if(Focused == -1 || Focused == ID_CUSTITEM ||
           (loc > maxcell && !IsSet(ppShowCustItem)))
          loc = IsSet(ppShowDefItem) ? ID_DEFITEM : (ID_MINITEM+1);
        else if(loc > maxcell && IsSet(ppShowCustItem))
          loc = ID_CUSTITEM;
        RefocusCell(loc);
      }
      break;
 
    case VK_DOWN: {
        int loc = Focused+NColumns;
        int maxcell = Cells->Size()-1;
        if(Focused == -1)
          loc = IsSet(ppShowDefItem) ? ID_DEFITEM : (ID_MINITEM+1);
        else if(Focused == ID_DEFITEM)
          loc = ID_MINITEM+1;
        else if(Focused == ID_CUSTITEM && IsSet(ppShowDefItem))
          loc = ID_DEFITEM;
        else if(loc >= maxcell && IsSet(ppShowCustItem)){
          loc = ID_CUSTITEM;
        }
        else if(loc >= maxcell && IsSet(ppShowDefItem)){
          loc = ID_DEFITEM;
        }
        else{
          if(loc > maxcell)
            loc -= NRows*NColumns;
          if(loc < ID_DELTA)
            loc += NRows;
        }
        RefocusCell(loc);
      }
      break;
 
    case VK_UP:{
        int loc = Focused-NColumns;
        int maxcell = Cells->Size()-1;
        if(Focused == -1 || Focused == ID_DEFITEM)
          loc = IsSet(ppShowCustItem) ? ID_CUSTITEM : maxcell;
        else if(Focused == ID_CUSTITEM)
          loc = (maxcell-ID_DELTA)/NColumns*NColumns+ID_DELTA;
        else if(loc < ID_DELTA && IsSet(ppShowDefItem))
          loc = ID_DEFITEM;
        else if(loc < ID_DELTA)
          loc += NRows*NColumns;
        RefocusCell(loc);
      }
      break;
 
    case VK_HOME:
      RefocusCell(IsSet(ppShowDefItem) ? ID_DEFITEM : (ID_MINITEM+1));
      break;
 
    case VK_END:
      RefocusCell(IsSet(ppShowCustItem) ? ID_CUSTITEM : Cells->Size()-1);
      break;
  }
}
 
//
// WM_KEYUP handler. Restore state of button and notify parent
//
void
TGridPicker::EvKeyUp(uint key, uint /*repeatCount*/, uint /*flags*/)
{
  if (IsSet(ppPushed) && (key == VK_SPACE || key == VK_RETURN)){
    SetSelection(Focused-ID_DELTA);
    Clear(ppPushed);
    if(IsSet(ppButtonSel)){
      Clear(ppButtonSel);
      (*Cells)[ID_CUSTITEM]->Select(false);
      InvalidateRect((*Cells)[ID_CUSTITEM]->Bounds,true);
 
      Set(ppCustomOpen);
      if(!CallCustomBox()){
        Clear(ppCustomOpen);
        NotifyParent(BN_CLICKED);
        ExitPicker(true);
        return;
      }
      Clear(ppCustomOpen);
 
      if(Selected >= 0)
        (*Cells)[Selected]->Select(false);
      Selected = ID_CUSTITEM;
      (*Cells)[ID_CUSTITEM]->Select(true);
    }
    else{
      NotifyParent(BN_CLICKED);
      ExitPicker(true);
    }
  }
}
 
//
//
//
void
TGridPicker::EvCancelMode()
{
  ClearCell();
  ClearCapture();
}
 
//
//
//
void
TGridPicker::ClearCell()
{
   if(Focused >= 0){
     (*Cells)[Focused]->LeaveMouse();
    InvalidateRect((*Cells)[Focused]->GetBounds(),true);
    Focused = -1;
  }
   if(IsSet(ppButtonSel)){
    Clear(ppButtonSel);
    (*Cells)[ID_CUSTITEM]->Select(false);
    InvalidateRect((*Cells)[ID_CUSTITEM]->Bounds,true);
  }
  if(IsSet(ppMessageTips))
     SetStatusBarMessage(-1);
  if(IsSet(ppShowTipsCell)){
    TLocalTipCell* cell = TYPESAFE_DOWNCAST((*Cells)[ID_STATITEM], TLocalTipCell);
    if(cell){
      cell->SetText(_T(""));
      InvalidateRect(cell->GetBounds(),true);
    }
  }
}
 
//
// Release caption if we are in 'capture' mode. Reset internal flags
// appropriately.
//
void
TGridPicker::ClearCapture()
{
  if (GetCapture() == *this)
    ReleaseCapture();
  Clear(ppPushed);
}
 
//
// ??????????????????????????????
// Maeby better to use TEnabler mechanism
//
tstring
TGridPicker::LoadTipText(int resId)
{
  tstring tipText = LoadString(resId);
  if(tipText.length() == 0)
  {
    TModule* module = TModule::FindResModule(resId/16+1, RT_STRING);
    if (module)
      tipText = module->LoadString(resId);
  }
  if (tipText.length() > 0)
  {
    tstring::size_type i = tipText.find_first_of(_T('\n'));
    if (i != tstring::npos)
      tipText = tipText.substr(i + 1);
    else
    {
      TWindow* parent = GetParentO();
      TDecoratedFrame* frame = parent ? TYPESAFE_DOWNCAST(parent, TDecoratedFrame) : 0;
      while (parent && !frame)
      {
        parent = parent->GetParentO();
        if (parent)
          frame = TYPESAFE_DOWNCAST(parent, TDecoratedFrame);
      }
      tstring hint;
      if (frame)
        hint = frame->GetHintText(resId, htTooltip);
      tipText = hint;
    }
  }
  return tipText;
}
 
//
// We display a message on the status bar.
//
void
TGridPicker::SetStatusBarMessage(int id)
{
  TWindow* parent= GetParentO();
  TDecoratedFrame* frame= parent ? TYPESAFE_DOWNCAST(parent, TDecoratedFrame) : 0;
  while (parent && !frame){
    parent = parent->GetParentO();
    if (parent)
      frame = TYPESAFE_DOWNCAST(parent, TDecoratedFrame);
  }
  if (frame){
    if (id > 0)
      frame->HandleMessage(WM_MENUSELECT, id, 0);
    else
      frame->HandleMessage(WM_MENUSELECT, 0xFFFF0000, 0);
    frame->HandleMessage(WM_ENTERIDLE, MSGF_MENU);
  }
}
 
//------------------------------------------------------------------------------
// class TPopupPicker
// ~~~~~ ~~~~~~~~~~~~
//
DEFINE_RESPONSE_TABLE1(TPopupPicker, TGridPicker)
  EV_WM_KILLFOCUS,
  EV_WM_ACTIVATEAPP,
END_RESPONSE_TABLE;
 
//
TPopupPicker::TPopupPicker(TWindow* parent, int id, int x, int y, int w, int h,
             TModule* module)
:
  TGridPicker(parent, id, x, y, w, h, module)
{
  ModifyStyle(WS_VISIBLE|WS_CHILD,WS_POPUP);
  ModifyExStyle(0, WS_EX_TOPMOST);
}
 
//
TPopupPicker::TPopupPicker(TWindow* parent, int resourceId, TModule* module)
:
  TGridPicker(parent, resourceId, module)
{
}
 
//
void
TPopupPicker::GetWindowClass(WNDCLASS& wndClass)
{
  TGridPicker::GetWindowClass(wndClass);
  wndClass.style |= CS_SAVEBITS;
}
 
//
void
TPopupPicker::Paint(TDC& dc, bool erase, TRect& rect)
{
  TRect crect = GetWindowRect();
  ::MapWindowPoints(HWND_DESKTOP, *this, LPPOINT(&crect), 2);
  TUIBorder(crect, TUIBorder::ButtonUp, TUIBorder::Adjust|TUIBorder::Rect).Paint(dc);
 
  TGridPicker::Paint(dc, erase, rect);
}
 
 
//
// WM_LBUTTONDOWN handler. Grab focus and update button's state to be in
// 'pushed' mode.
//
void
TPopupPicker::EvLButtonDown(uint modKeys, const TPoint& point)
{
  TGridPicker::EvLButtonDown(modKeys, point);
 
  if(!GetClientRect().Contains(point))
    ExitPicker(false);
}
 
//
void
TPopupPicker::EvKillFocus(THandle hWndGetFocus )
{
  TGridPicker::EvKillFocus(hWndGetFocus);
  ReleaseCapture();
 
  if (!IsSet(ppCustomOpen))
    ExitPicker(false);
}
 
// Another application has the focus, so we hide the picker window.
void
TPopupPicker::EvActivateApp(bool active, DWORD taskId)
{
  TGridPicker::EvActivateApp(active, taskId);
 
  if ((!active) && !IsSet(ppCustomOpen))
    ExitPicker(false);
}
 
//
void
TPopupPicker::ExitPicker(bool status)
{
  ReleaseCapture();
  ShowWindow(SW_HIDE);
  if(status)
    Set(ppSelected);
  else
    Clear(ppSelected);
}
 
//
bool
TPopupPicker::ShowPicker(TPoint& p, TRect& rect) // (pt, rect)
{
  TSize   size(Attr.W, Attr.H);
  TSize   checksize(size.cx + 1, size.cy + 1);
  TPoint   point(p);
  TSize   scrSize(TUIMetric::CxScreen,TUIMetric::CyScreen);
 
  // Check the vertical position.
  //
  if (point.y + size.cy > scrSize.cy) {
    if ((rect.top >= 0) && (rect.bottom >= 0) && (rect.top - checksize.cy >= 0))
      point.y = rect.top - checksize.cy;
    else point.y = scrSize.cy - checksize.cy;
  }
 
  // Check the horizontal position.
  //
  if (point.x + checksize.cx > scrSize.cx)
    point.x = scrSize.cx - checksize.cx;
  SetWindowPos(HWND_TOPMOST, point.x, point.y, size.cx, size.cy, SWP_SHOWWINDOW);
  SetCapture();
 
  HWND hWnd = GetHandle();
  while(::IsWindow(hWnd) && ::IsWindowVisible(hWnd))
    GetApplication()->PumpWaitingMessages();
 
  if(!::IsWindow(hWnd))
    return false;
 
  bool Ok = IsSet(ppSelected);
  Clear(ppSelected);
  return Ok;
}
//------------------------------------------------------------------------------
//
// class TPickerGadget
// ~~~~~ ~~~~~~~~~~~~~
//
TPickerGadget::TPickerGadget(TPopupPicker&  picker, TResId glyphResIdOrIndex,
  TStyle style, TPopupType poptype, TType type, bool enabled, TState state,
  bool sharedGlyph, uint numChars)
:
  TPopupButtonGadget(picker.GetId(), glyphResIdOrIndex, style, poptype, type,
                     enabled, state, sharedGlyph, numChars),
  Picker(&picker),
  Selected(0)
{
  // it does not have style WS_CHILD, so this member should be
  // menu handle or 0;
  picker.GetWindowAttr().Id = 0;
}
 
//
//
//
TPickerGadget::~TPickerGadget()
{
  if(Picker)
    Picker->Destroy(0);
  delete Picker;
}
 
//
//
//
void
TPickerGadget::PopupAction()
{
  // do something
  TRect rect = GetBounds();
  TPoint p2(rect.TopLeft());
  Window->ClientToScreen(p2);
  rect.right = p2.x + rect.Width();
  rect.bottom = p2.y + rect.Height();
  rect.left = p2.x;
  rect.top = p2.y;
  p2.y = rect.bottom;
 
  // We tell the picker where the picker has to be displayed.
  HWND hWnd = *Picker;
  if(Picker->ShowPicker(p2, rect))
    GetSelection();
 
  if(!IsWindow(hWnd))
    return;
 
  // and call inherited class
  //
  TPopupButtonGadget::PopupAction();
   TPoint tp;
   Activate(tp);// send command message to parent ?????????????
}
 
//
//
//
void
TPickerGadget::Created()
{
  TPopupButtonGadget::Created();
  if (Window->GetHandle() && !Picker->GetHandle()){
    Picker->Create();
    Picker->ShowWindow(SW_HIDE);
  }
  if(Picker->GetHandle())
    Picker->GetWindowAttr().Id = GetId();
}
 
//
//
//
void
TPickerGadget::Inserted()
{
  TPopupButtonGadget::Inserted();
  Picker->SetParent(Window);
  GetSelection();
}
 
//
//
//
void
TPickerGadget::GetSelection()
{
  TPickerCell* cell = Picker->GetSelectedCell();
  int sel = Picker->GetSelection();
  if(sel == -1) // default selection
    cell = Picker->GetDefaultCell();
 
  if(!cell)
    cell = Picker->GetCustomCell();
  if(cell)
    Selected = cell;
}
 
//------------------------------------------------------------------------------
//
// class TColorPicker
// ~~~~~ ~~~~~~~~~~~~
//
// Gray default custom colors for SelectColor Dlg
struct TCustomColors
#if defined(BI_MULTI_THREAD_RTL)
                : public TLocalObject
#endif
{
  TCustomColors();
 
  TColor Colors[16];
#if defined(BI_MULTI_THREAD_RTL)
//    TMRSWSection  Lock;
#endif
};
 
TCustomColors::TCustomColors()
{
  Colors[0] = RGB(0x01, 0x01, 0x01);
  Colors[1] = RGB(0x10, 0x10, 0x10);
  Colors[2] = RGB(0x20, 0x20, 0x20);
  Colors[3] = RGB(0x30, 0x30, 0x30);
 
  Colors[4] = RGB(0x40, 0x40, 0x40);
  Colors[5] = RGB(0x50, 0x50, 0x50);
  Colors[6] = RGB(0x60, 0x60, 0x60);
  Colors[7] = RGB(0x70, 0x70, 0x70);
 
  Colors[8] = RGB(0x80, 0x80, 0x80);
  Colors[9] = RGB(0x90, 0x90, 0x90);
  Colors[10] = RGB(0xA0, 0xA0, 0xA0);
  Colors[11] = RGB(0xB0, 0xB0, 0xB0);
 
  Colors[12] = RGB(0xC0, 0xC0, 0xC0);
  Colors[13] = RGB(0xD0, 0xD0, 0xD0);
  Colors[14] = RGB(0xE0, 0xE0, 0xE0);
  Colors[15] = RGB(0xF0, 0xF0, 0xF0);
}
 
//
// Static instance of the colors
//
static TCustomColors& GetCustomColors()
{
#if defined(BI_MULTI_THREAD_RTL)
  static TTlsContainer<TCustomColors> customColors;
  return customColors.Get();
#else
  static TCustomColors customColors;
  return customColors;
#endif
};
 
namespace
{
  //
  // Ensure singleton initialization at start-up (single-threaded, safe).
  //
  TCustomColors& InitCustomColors = GetCustomColors();
}
 
#if defined(BI_MULTI_THREAD_RTL)
#define LOCKCOLORS //TMRSWSection::TLock Lock(GetBrushCache().Lock);
#else
#define LOCKCOLORS
#endif
 
//
// Build a response table for all messages/commands handled by the application.
//
DEFINE_RESPONSE_TABLE1(TColorPicker, TPopupPicker)
  EV_WM_PALETTECHANGED,
  EV_WM_QUERYNEWPALETTE,
END_RESPONSE_TABLE;
 
//
TColorPicker::TColorPicker(TWindow* parent, int id, int x, int y, int w, int h,
             TModule* module)
:
  TPopupPicker(parent, id, x, y, w, h, module),
  Palette(0),
  CustomColors(GetCustomColors().Colors),
  WorkPalette(0),
  PaletteRealized(false)
{
}
 
//
TColorPicker::TColorPicker(TWindow* parent, int resourceId, TModule* module)
:
  TPopupPicker(parent, resourceId, module),
  Palette(0),
  CustomColors(GetCustomColors().Colors),
  WorkPalette(0),
  PaletteRealized(false)
{
}
 
//
TColorPicker::~TColorPicker()
{
  delete Palette;
}
 
//
void
TColorPicker::SetupWindow()
{
/* // palette not working for now ??????????????????
  if (TScreenDC().GetDeviceCaps(RASTERCAPS) & RC_PALETTE){
    TAPointer<char> __clnObj = new char[sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*Cells->Size()];
    LOGPALETTE* lpPalette = (LOGPALETTE*)(char*)__clnObj;
 
    lpPalette->palVersion = 0x300;
    lpPalette->palNumEntries = (uint16)Cells->Size();
    for(int i = 0; i < Cells->Size(); i++){
      TColorCell* cell = TYPESAFE_DOWNCAST(GetSelectedCell(), TColorCell);
      if(cell){
        lpPalette->palPalEntry[i].peRed   = cell->GetColor().Red();
        lpPalette->palPalEntry[i].peGreen = cell->GetColor().Green();
        lpPalette->palPalEntry[i].peBlue  = cell->GetColor().Blue();
        lpPalette->palPalEntry[i].peFlags = PC_RESERVED;
      }
    }
    Palette = new TPalette(lpPalette);
  }
*/
  TPopupPicker::SetupWindow();
}
 
//
void
TColorPicker::SetCustomColors(TColor* colors)
{
  if(colors)
    CustomColors = colors;
  else
    CustomColors = GetCustomColors().Colors;
}
 
//
void
TColorPicker::NotifyParent(uint code)
{
  TColorCell* cell = TYPESAFE_DOWNCAST(GetSelectedCell(), TColorCell);
  if(cell){
    const HWND w = Target ? Target->GetHandle() : ::GetParent(*this);
    const HWND c = reinterpret_cast<HWND>(static_cast<UINT_PTR>(cell->GetColor().GetValue()));
    SendNotification(w, GetDlgCtrlID(), code, c);
  }
}
 
//
void
TColorPicker::Paint(TDC& dc, bool erase, TRect& rect)
{
  if (Palette){
    WorkPalette = new TPalette(*Palette);
    dc.SelectObject(*WorkPalette);
    PaletteRealized = (dc.RealizePalette() > 0);
 
    // set palette index value
    if(PaletteRealized){
      for(int i = 3; i < (int)Cells->Size(); i++){
        TColorCell* cell = TYPESAFE_DOWNCAST((*Cells)[i], TColorCell);
        if(cell)
          cell->SetColor(TColor::CreateFromPaletteIndex(i));
      }
    }
  }
 
  TPopupPicker::Paint(dc, erase, rect);
 
  // and reset colors
  if(WorkPalette){
    if(PaletteRealized){
      uint ncolors = WorkPalette->GetNumEntries();
      if(ncolors){
        TAPointer<PALETTEENTRY> _entries(new PALETTEENTRY[ncolors]);
        WorkPalette->GetPaletteEntries(0, (uint16)ncolors, _entries);
 
        for(int i = 3; i < (int)Cells->Size(); i++){
          TColorCell* cell = TYPESAFE_DOWNCAST((*Cells)[i], TColorCell);
          if(cell)
            cell->SetColor(TColor(_entries[i]));
        }
      }
    }
    dc.RestorePalette();
    delete WorkPalette;
    WorkPalette = 0;
  }
}
 
// Someone has changed the palette. We must realize our palette again.
//
void
TColorPicker::EvPaletteChanged(HWND hWndPalChg)
{
  TPopupPicker::EvPaletteChanged(hWndPalChg);
  if (hWndPalChg != GetHandle())
    Invalidate();
}
 
// Give us the chance to realize our palette.
//
bool
TColorPicker::EvQueryNewPalette()
{
  Invalidate();
  return TPopupPicker::EvQueryNewPalette() | PaletteRealized;
}
 
//
//
bool
TColorPicker::CallCustomBox()
{
  TColorCell* cell = TYPESAFE_DOWNCAST(GetSelectedCell(), TColorCell);
  TColor color = TColor::Black;
  if(cell)
    color = cell->GetColor();
 
  TChooseColorDialog::TData choose;
 
  choose.Flags = CC_RGBINIT;
  choose.Color = color;
  choose.CustColors = CustomColors;
  if (TChooseColorDialog(this, choose).Execute() == IDOK) {
    CustomColor = choose.Color;
    return true;
  }
  return false;
}
 
//------------------------------------------------------------------------------
//
// class TColorPickerGadget
// ~~~~~ ~~~~~~~~~~~~~~~~~~
//
TColorPickerGadget::TColorPickerGadget(TColorPicker& picker,
    TResId glyphResIdOrIndex, TStyle style, TPopupType poptype, TType type,
    bool enabled, TState state, bool sharedGlyph, uint numChars)
:
  TPickerGadget(picker, glyphResIdOrIndex, style, poptype, type, enabled,
                state,sharedGlyph, numChars),
  ColorSel(TColor::None)
{
}
 
void
TColorPickerGadget::GetSelection()
{
  int sel = Picker->GetSelection();
  if(sel == -2){
    TColorPicker* cPicker = TYPESAFE_DOWNCAST(Picker, TColorPicker);
    if(cPicker)
      ColorSel = cPicker->GetCustomColor();
  }
  else{
    TPickerGadget::GetSelection();
    TColorCell* cell = TYPESAFE_DOWNCAST(Selected, TColorCell);
    if(cell)
      ColorSel = cell->GetColor();
  }
}
 
//
void
TColorPickerGadget::GetFillRect(TRect& rect, const TRect& faceRect)
{
  TSize size = CelArray ? CelArray->CelSize() : Window->GetCelArray().CelSize();
 
  rect.left   = faceRect.left+(faceRect.Width()-size.cx)/2;
  rect.top     = faceRect.bottom-5;
  rect.right   = rect.left + size.cx;
  rect.bottom = faceRect.bottom-1;
}
 
//
void
TColorPickerGadget::PaintFace(TDC& dc, const TRect& rect)
{
  TPickerGadget::PaintFace(dc, rect);
 
  // now add color rectangle
  if(GetEnabled() && ColorSel != TColor::None){
 
    // Copy only the RGB values for the color that will be draw
    //
    TColor color(ColorSel.Red(), ColorSel.Green(), ColorSel.Blue());
 
    TRect fillRect;
    GetFillRect(fillRect, rect);
 
    dc.FillRect(Pressed ? fillRect.Offset(1,1) : fillRect, TBrush(color));
 
    TBrush shbr(TColor::Sys3dShadow);
    dc.FrameRect(fillRect, shbr);
  }
}
 
//
// class TBitmapPickerGadget
//
//
// class TBitmapPickerGadget
// ~~~~~ ~~~~~~~~~~~~~~~~~~~
//
TBitmapPickerGadget::TBitmapPickerGadget(TPopupPicker& picker,
    TResId glyphResIdOrIndex, TStyle style, TPopupType poptype, TType type,
    bool enabled, TState state, bool sharedGlyph, uint numChars)
:
  TPickerGadget(picker, glyphResIdOrIndex, style, poptype, type, enabled,
                state,sharedGlyph, numChars)
{
}
 
//
// helper functions
//
void
TBitmapPickerGadget::CopyCellBitmap()
{
  TBitmapCell* cell = TYPESAFE_DOWNCAST(Selected, TBitmapCell);
  if(cell){
    TCelArray& dstArray = CelArray ? *CelArray : Window->GetCelArray();
    TCelArray& srcArray = *cell->GetCelArray();
    TMemoryDC srcDC((TBitmap&)srcArray);
    TMemoryDC dstDC((TBitmap&)dstArray);
 
    TSize size(dstArray.CelSize().cx,dstArray.CelSize().cx*dstArray.NumRows());
    TRect dstRect(dstArray.CelOffset(GlyphIndex), size);
 
    int curRow = srcArray.CurRow();
    TRect srcRect(srcArray.CelRect(cell->GetIndex()));
    srcArray.SetCurRow(curRow);
 
    size = TSize(srcRect.Size());
    srcRect = TRect(srcRect.TopLeft(),TSize(size.cx, size.cy*srcArray.NumRows()));
 
    //rect.Inflate(-2,-2);
 
    dstDC.StretchBlt(dstRect, srcDC, srcRect);
  }
}
 
//
//
//
void
TBitmapPickerGadget::BuildCelArray()
{
  TPickerGadget::BuildCelArray();
  CopyCellBitmap();
}
 
//
//
//
void
TBitmapPickerGadget::GetSelection()
{
  TPickerCell* cell = Selected;
 
  TPickerGadget::GetSelection();
  if(Selected && cell != Selected)
    CopyCellBitmap();
}
 
 
} // OWL namespace
 
//==============================================================================
 

V1027 Pointer to an object of the 'TCelArray' class is cast to unrelated 'TBitmap' class.

V1027 Pointer to an object of the 'TCelArray' class is cast to unrelated 'TBitmap' class.

V811 Decreased performance. Excessive type casting: string -> char * -> string. Consider inspecting first argument of the function SetText.

V832 It's better to use '= default;' syntax instead of empty constructor body.

V820 The 'hint' variable is not used after copying. Copying can be replaced with move/swap for optimization.