//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1998, by Yura Bidus, All Rights Reserved
//
/// \file
/// Implementation of class TDrawItemProxy, TDrawItem,TButtonTextDrawItem,
/// TDrawMenuItem, TDrawMenuItemProxy. Owner draw family.
//
// Note this classes stil under development!!!!!!!!!!!!!!!
//
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/uimetric.h>
#include <owl/template.h>
#include <owl/gadgetwi.h>
#include <owl/celarray.h>
#include <owl/uihelper.h>
#include <owl/glyphbtn.h>
 
#include <owl/drawitem.h>
#include <owl/resource.h>
 
#include <algorithm>
 
using namespace std;
 
namespace owl {
 
//
// class TDrawItemProxy
// ~~~~~ ~~~~~~~~~~~~~~
/// Constructs a TDrawItemProxy object using the specified font. Ownership of the
/// font transfers to the new object.
//
TDrawItemProxy::TDrawItemProxy(TFont* font)
:
  Font(font ? font : new TGadgetWindowFont()), CelArray(0), DeleteCel(false)
{
  ItemArray = new TDrawItemArray;
}
//
/// Deletes Font. If DeleteCel is true, delets CelArray.
//
TDrawItemProxy::~TDrawItemProxy()
{
  delete Font;
  if(DeleteCel)
    delete CelArray;
  delete ItemArray;
}
//
/// Deletes Font and sets it to font. Ownership of font transfers to the
/// TDrawItemProxy.
//
void TDrawItemProxy::SetFont(TFont* font)
{
  delete Font;
  Font = font;
}
//
/// If DeleteCel is true, deletes CelArray. CelArray is then set to celarray and
/// DeleteCel is set to del.
//
void TDrawItemProxy::SetCelArray(TCelArray* celarray, TAutoDelete del)
{
  if(DeleteCel)
    delete CelArray;
  CelArray = celarray;
  DeleteCel = del == AutoDelete;
}
//
/// Loads a TDib with resource id resId from module. It then uses this TDib and
/// count to create a new TCelArray. SetCelArray is then called with this TCelArray
/// and AutoDelete.
//
void TDrawItemProxy::SetCelArray(TResId resId, uint count, TModule* module)
{
  TBtnBitmap* bitmap = new TBtnBitmap(*module, resId, TColor::LtGray);
  SetCelArray(new TCelArray(bitmap,count),AutoDelete);
}
//
/// Adds item to ItemArray.
//
void TDrawItemProxy::RegisterItem(TDrawItem* item)
{
  ItemArray->Add(item);
}
//
//---------------------------------------------------------------------------
//
// class TButtonTextDrawItem
// ~~~~~ ~~~~~~~~~~~~~~~~~~~
//
const int TextSpaceH = 2;
const int TextSpaceV = 2;
const int TextSpaceE = 15;
const int ButtonSpaceH = 0;
const int ButtonSpaceV = 0;
//---------------------------------------------------------------------------------------
//
/// Constructs a TButtonTextDrawItem with proxy as it's parent.
//
TButtonTextDrawItem::TButtonTextDrawItem(TDrawItemProxy* proxy)
:
  Text(0),
  Index(-1),
  Align(aLeft),
  Style(sNone),
  LayoutStyle(lTextRight),
  Flags(0),
  Font(0),
  CelArray(0),
  DeleteCel(false),
  Proxy(proxy)
{
}
//
/// Destroys a TButtonTextDrawItem object. If DeleteCel is true, deletes CelArray.
//
TButtonTextDrawItem::~TButtonTextDrawItem()
{
  if(DeleteCel)
    delete   CelArray;
  delete[] Text;
  delete   Font;
}
//
/// Deletes Text and clears the text style. If text is not NULL, a copy is assigned
/// to Text and the sText style is added to Style.
//
void
TButtonTextDrawItem::SetText(LPCTSTR text)
{
  delete[] Text;
  Text = 0;
  uint style = (uint)Style;
  style &= ~sText;
  if(text){
    Text    = strnewdup(text);
    // replace all '\a' to '\t'
    // '\a' in *.rc becomes '\b' in *.res
    tchar c = _T('\b');
    tchar* p = _tcschr(Text,c);
    while(p){
      *p = _T('\t');
      p = _tcschr(Text,_T('\b'));
    }
    style |= sText;
  }
  Style = (TStyle)style;
}
//
/// Index is set to index and the sBitmap style is cleared from Style. If index >=
/// 0, the sBitmap style is added to Style.
//
void
TButtonTextDrawItem::SetIndex(int index)
{
  Index = index;
  uint style = (uint)Style;
  style &= ~sBitmap;
  if(Index >=0)
    style |= sBitmap;
  Style = (TStyle)style;
}
//
/// Deletes Font and then assigns font to Font. Ownership of font is transferred to
/// this instance.
//
void
TButtonTextDrawItem::SetFont(TFont* font)
{
  delete Font;
  Font = font;
}
//
/// If DeleteCel is true, CelArray is deleted. celarray is assigned to CelArray and
/// del is assigned to DeleteCel.
//
void
TButtonTextDrawItem::SetCelArray(TCelArray* celarray, TAutoDelete del)
{
  if(DeleteCel)
    delete CelArray;
  CelArray = celarray;
  DeleteCel = del == AutoDelete;
}
//
/// A bitmap with resource id resId is loaded from module and used to create a
/// TCelArray with count cells. SetCelArray is then called with this TCelArray.
//
void
TButtonTextDrawItem::SetCelArray(TResId resId, uint count, TModule* module)
{
  TBtnBitmap* bitmap = new TBtnBitmap(*module, resId, TColor::LtGray);
  SetCelArray(new TCelArray(bitmap,count));
}
//
/// Extracts information from drawItem and calls Paint.
//
void
TButtonTextDrawItem::Draw(DRAWITEMSTRUCT & drawItem)
{
  Flags = drawItem.itemState;
 
  TDC dc(drawItem.hDC);
  TRect rect(drawItem.rcItem);
  Paint(dc, rect);
}
//
/// Calculates the area required to display the button and text.
//
void
TButtonTextDrawItem::Measure(MEASUREITEMSTRUCT & measureItem)
{
  TSize textSize;
  GetTextSize(textSize);
 
  TSize btnSize(0,0);
  if(GetStyle() & TButtonTextDrawItem::sBitmap)
    GetButtonSize(btnSize);
 
  measureItem.itemWidth    = textSize.cx + btnSize.cx;
  measureItem.itemHeight  = std::max(textSize.cy,btnSize.cy);
}
//
/// Does an lstrcmp on Text from the instances contained in drawItem.
//
int
TButtonTextDrawItem::Compare(COMPAREITEMSTRUCT & compareItem)
{
  TButtonTextDrawItem* item1 = (TButtonTextDrawItem*)compareItem.itemData1;
  TButtonTextDrawItem* item2 = (TButtonTextDrawItem*)compareItem.itemData2;
  return lstrcmp(item1->GetText(), item2->GetText());
}
//
/// If selected returns TColor::SysActiveCaption; otherwise returns
/// TColor::SysWindow.
//
TColor
TButtonTextDrawItem::GetBkColor()
{
  return IsSelected() ? TColor::SysActiveCaption : TColor::SysWindow;
}
//
/// If selected, returns TColor::Sys3dHilight if a 3d User interface is in use or
/// TColor::SysGrayText otherwise.
//
TColor
TButtonTextDrawItem::GetTextColor()
{
  if (IsSelected() || !IsEnabled())
    return TColor::Sys3dHilight;
  else
    return TColor::SysWindowText;
}
//
/// Calculates the size of the rectangle need to paint the text.
//
void
TButtonTextDrawItem::GetTextSize(TSize& size)
{
  TFont* font = Font;
  if(!font)
    font = Proxy->GetFont();
 
  TScreenDC dc;
 
  if(font)
   dc.SelectObject(*font);
 
  size = dc.GetTextExtentPoint32(GetText());
 
  if(font)
    dc.RestoreFont();
}
//
/// Paint function.
//
void
TButtonTextDrawItem::Paint(TDC& dc, TRect& rect)
{
  TRect textRect, btnRect;
 
  Layout(rect, textRect, btnRect);
 
  // 1. Erase all
  TColor oldBkColor = dc.SetBkColor(GetBkColor());
 
  dc.TextRect(rect);
 
   PaintText(dc, textRect);
 
  PaintBitmap(dc, btnRect);
 
  dc.SetBkColor(oldBkColor);
 
  PaintBorder(dc, rect);
}
//
/// Layout Text and Bitmap
///
/// Determines the bounding rectangles for the current style.
//
void
TButtonTextDrawItem::Layout(const TRect& faceRect, TRect& textRect, TRect& btnRect)
{
  TSize textSize;
  GetTextSize(textSize);
 
  TSize btnSize;
  GetButtonSize(btnSize);
 
  switch(LayoutStyle){
 
    case lTextLeft:
      textRect = TRect(faceRect.TopLeft(), TSize(textSize.cx,faceRect.Height()));
      btnRect  = TRect(faceRect.left+textSize.cx+ButtonSpaceH,faceRect.top+ButtonSpaceV,
                       faceRect.right-ButtonSpaceH,faceRect.bottom-ButtonSpaceV);
       break;
 
    case lTextRight:
      btnRect = TRect(faceRect.left+ButtonSpaceH, faceRect.top+ButtonSpaceV,
                      faceRect.left+btnSize.cx-ButtonSpaceH, faceRect.bottom-ButtonSpaceV);
      textRect = TRect(btnRect.right+TextSpaceH+ButtonSpaceH,faceRect.top,
                       faceRect.right-TextSpaceH, faceRect.bottom);
 
      break;
 
    case lTextTop:
       textRect = TRect(faceRect.TopLeft(), TSize(faceRect.Width()-TextSpaceH,textSize.cy));
      btnRect  = TRect(faceRect.left+ButtonSpaceH,faceRect.top+textSize.cy+TextSpaceV,
                       faceRect.right-ButtonSpaceH, faceRect.bottom-ButtonSpaceV);
       break;
 
    case lTextBottom:
       textRect = TRect(faceRect.left,faceRect.bottom-textSize.cy,
                      faceRect.right,faceRect.bottom);
       btnRect  = TRect(faceRect.left+ButtonSpaceH,faceRect.top+ButtonSpaceV,
                      faceRect.right-ButtonSpaceH, faceRect.bottom-textSize.cy-ButtonSpaceV);
      break;
  }
}
//
/// Paint the text.
//
void
TButtonTextDrawItem::PaintText(TDC& dc, TRect& rect)
{
  if((Style&sText)==0)
    return;
 
  TFont* font = Font;
  if (!font)
    font = Proxy->GetFont();
  if(font)
   dc.SelectObject(*font);
 
   TColor oldTxColor  = dc.SetTextColor(GetTextColor());
 
  uint format =  DT_SINGLELINE|DT_EXPANDTABS;
  switch(Align){
    case aLeft:
      format |= DT_LEFT;
      break;
    case aRight:
      format |= DT_RIGHT;
      break;
    case aCenter:
      format |= DT_CENTER;
      break;
  }
  switch(LayoutStyle){
    case lTextLeft:
    case lTextRight:
      format |= DT_VCENTER;
      break;
    case lTextTop:
      format |= DT_VCENTER;//DT_BOTTOM;
      break;
    case lTextBottom:
      format |= DT_VCENTER;//DT_TOP;
      break;
  }
 
  // Create a UI Face object for this button & let it paint the button face
  //
  TRect  tRect(rect);
  TPoint dstPt(tRect.TopLeft());
 
  TUIFace face(tRect, Text, GetBkColor(), format);
  if ((!IsEnabled()||IsGrayed()) && !IsSelected())
    face.Paint(dc, dstPt, TUIFace::Disabled, false, false);
  else
    face.Paint(dc, dstPt, TUIFace::Normal, false, false);
 
  dc.SetTextColor(oldTxColor);
 
  if(font)
    dc.RestoreFont();
}
//
/// Calculates the size of button.
//
void
TButtonTextDrawItem::GetButtonSize(TSize& btnSize)
{
  btnSize = TSize(0,0);
  if(Index == sepNoBitmap) // == -2
    return;
  TCelArray* celArray = CelArray ? CelArray : Proxy->GetCelArray();
  if(celArray)
    btnSize = celArray->CelSize();
}
//
/// Paint the border of the gadget based on the BorderStyle member
//
void
TButtonTextDrawItem::PaintBorder(TDC& dc, TRect& boundsRect)
{
  if(IsFocused())
    dc.DrawFocusRect(boundsRect);
}
//
/// Paint the bitmap.
//
void
TButtonTextDrawItem::PaintBitmap(TDC& dc, TRect& rect)
{
  if((Style&sBitmap)==0 || Index < 0)
    return;
 
  // Determine which CelArray to paint from: ours or our Window's
  //
  TCelArray& celArray = CelArray ? *CelArray : *Proxy->GetCelArray();
  // Create a UI Face object for this button & let it paint the button face
  celArray.BitBlt(Index, dc, rect.left, rect.top);
}
//////////////////////////////////////////////////////////////////////////////////////
//
//
 
//
/// Called with the proxy parent, the command it, the index in the menu and the text
/// to display.
//
TDrawMenuItem::TDrawMenuItem(TDrawItemProxy* proxy, int cmdId, int index, LPCTSTR title)
:
  TButtonTextDrawItem(proxy),CmdId(cmdId),CheckPainter(0)
{
  SetText(title);
  SetIndex(index);
}
 
//
/// String-aware overload
//
TDrawMenuItem::TDrawMenuItem(TDrawItemProxy* proxy, int cmdId, int index, const tstring& title)
  : TButtonTextDrawItem(proxy), CmdId(cmdId), CheckPainter(0)
{
  SetText(title.c_str());
  SetIndex(index);
}
 
//
//
//
void
TDrawMenuItem::GetTextSize(TSize& size)
{
  TButtonTextDrawItem::GetTextSize(size);
  size.cx += TextSpaceE;
  if((GetStyle() & TButtonTextDrawItem::sBitmap)==0)
    size.cx += TextSpaceE;
  size.cy = std::max((int)size.cy, 16);
}
//
/// Get the size of the bitmap button.
//
void
TDrawMenuItem::GetButtonSize(TSize& btnSize)
{
  btnSize = TSize(0,0);
  if(Index == sepNoBitmap) // == -2
    return;
  TCelArray* celArray = CelArray ? CelArray : Proxy->GetCelArray();
  if(celArray){
    btnSize = celArray->CelSize();
    btnSize.cx  += 3;
    btnSize.cy  += 3;
  }
}
//
/// If the menu item is selected returns TColor::SysActiveCaption; otherwise returns
/// TColor::SysMenu.
//
TColor
TDrawMenuItem::GetBkColor()
{
  return IsSelected() ? TColor::SysActiveCaption : TColor::SysMenu;
}
//
/// Returns the text color.
//
TColor
TDrawMenuItem::GetTextColor()
{
  if (IsSelected() || !IsEnabled())
    return TColor::Sys3dHilight;
  else
    return TColor::SysMenuText;
}
//
/// Paint the bitmap on the menu entry.
//
void
TDrawMenuItem::PaintBitmap(TDC& dc, TRect& rect)
{
  if(((Style&sBitmap)==0 || Index < 0) && CheckPainter==0)
    return;
 
  TColor oldBkColor = dc.SetBkColor(TColor::SysMenu);
  dc.TextRect(rect);
 
  if(CheckPainter){
 
    if(IsChecked())
      (this->*CheckPainter)(dc, rect);
    else
      PaintCheck_None(dc,rect);
 
    dc.SetBkColor(oldBkColor);
    return;
  }
 
  // Determine which CelArray to paint from: ours or our Window's
  //
  TCelArray& celArray = CelArray ? *CelArray : *Proxy->GetCelArray();
 
  // Calc the source rect from the celarray. The dest point of the glyph is
  // relative to the face rect.
  //
  TRect  srcRect(celArray.CelRect(Index));
 
  // Paint border
  //
  TUIBorder::TEdge edge = TUIBorder::TEdge(0);
  if(IsChecked())
    edge = TUIBorder::SunkenInner;
  else if(IsSelected()&&IsEnabled())
    edge = TUIBorder::RaisedInner;
  if(edge)
    TUIBorder(rect, edge).Paint(dc);
 
  rect.Inflate(-1,-1);
 
  // Create a UI Face object for this button & let it paint the button face
  //
  TUIFace face(rect, celArray.operator TBitmap&());
  TPoint dstPt(1,1);
 
  if (!IsEnabled())
    face.Paint(dc, srcRect, dstPt, TUIFace::Disabled, IsChecked());
  else if(IsGrayed())
    face.Paint(dc, srcRect, dstPt, TUIFace::Indeterm, IsChecked());
  else
#if 0
    face.Paint(dc, srcRect, (IsSelected() && !IsChecked()) ?
               dstPt.Offset(-1,-1) : dstPt, TUIFace::Normal, IsChecked());
#else
    face.Paint(dc, srcRect, dstPt, TUIFace::Normal, IsChecked());
#endif
  dc.SetBkColor(oldBkColor);
}
//
// Paint Text
//
void
TDrawMenuItem::PaintText(TDC& dc, TRect& rect)
{
  if((Style&sText)==0)
    return;
 
  TFont* font = Font;
  if (!font)
    font = Proxy->GetFont();
  if(font)
   dc.SelectObject(*font);
 
   TColor oldTxColor  = dc.SetTextColor(GetTextColor());
 
  uint format =  DT_SINGLELINE|DT_EXPANDTABS;
  switch(Align){
    case aLeft:
      format |= DT_LEFT;
      break;
    case aRight:
      format |= DT_RIGHT;
      break;
    case aCenter:
      format |= DT_CENTER;
      break;
  }
  switch(LayoutStyle){
    case lTextLeft:
    case lTextRight:
      format |= DT_VCENTER;
      break;
    case lTextTop:
      format |= DT_VCENTER;//DT_BOTTOM;
      break;
    case lTextBottom:
      format |= DT_VCENTER;//DT_TOP;
      break;
  }
 
  // DT_RIGHT for \t
  tstring cs1;
  tstring cs(Text);
  size_t t_pos = cs.find(_T("\t")); //JJH changed int -> size_t
 
  TRect   tRect(rect);
  tRect.right -= TextSpaceE;
 
  // Accelerator can be \b instead of \t (NOTE: \a in .rc make a \b in res)
  //
  if (t_pos == cs.npos)
    t_pos = cs.find(_T("\b"));
 
  if (t_pos != cs.npos)
  {
    cs1 = cs.substr(t_pos+1);
    cs  = cs.substr(0, t_pos);
    // Create a UI Face object for this button & let it paint the button face
    //
    TPoint  dstPt(tRect.TopLeft());
 
    TUIFace face1(tRect, cs.c_str(), GetBkColor(), format);
    format &= ~DT_LEFT;
    format |= DT_RIGHT;
    TUIFace face2(tRect, cs1.c_str(), GetBkColor(), format);
 
    if ((!IsEnabled()||IsGrayed()) && !IsSelected()){
      face1.Paint(dc, dstPt, TUIFace::Disabled, false, false);
      face2.Paint(dc, dstPt, TUIFace::Disabled, false, false);
    }
    else{
      face1.Paint(dc, dstPt, TUIFace::Normal, false, false);
      face2.Paint(dc, dstPt, TUIFace::Normal, false, false);
    }
  }
  else{
    // Create a UI Face object for this button & let it paint the button face
    //
    TPoint  dstPt(tRect.TopLeft());
 
    TUIFace face(tRect, Text, GetBkColor(), format);
    if ((!IsEnabled()||IsGrayed()) && !IsSelected())
      face.Paint(dc, dstPt, TUIFace::Disabled, false, false);
    else
      face.Paint(dc, dstPt, TUIFace::Normal, false, false);
  }
 
  dc.SetTextColor(oldTxColor);
 
  if(font)
    dc.RestoreFont();
}
//
/// If checked, clears the area in preparation for painting the check mark.
//
void
TDrawMenuItem::PaintCheckFace(TDC& dc, TRect& rect)
{
  if(IsChecked()){
    TColor oldBkColor = dc.SetBkColor(TColor::SysMenu);
    if(!IsSelected() || !IsEnabled())
      dc.FillRect(rect, TUIFace::GetDitherBrush());
    else
      dc.TextRect(rect);
    TUIBorder(rect, TUIBorder::Recessed).Paint(dc);
    dc.SetBkColor(oldBkColor);
  }
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// Check Draw functions
//
static TColor SelectColor(bool enabled)
{
  return enabled ? TColor::SysMenuText : TColor::Sys3dHilight;
}
//
///   Draw this:
/// \code
///   01234567
/// 0 ---x----
/// 1 ---xx---
/// 2 ---xxx--
/// 3 ---xxxx-
/// 4 ---xxx--
/// 5 ---xx---
/// 6 ---x----
/// 7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_3Angle(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+3,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+3,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 ---x----
  // 1 ---xx---
  // 2 ---xxx--
  // 3 ---xxxx-
  // 4 ---xxx--
  // 5 ---xx---
  // 6 ---x----
  // 7 --------
  //
  dc.SetPixel(point.x + 3, point.y + 0, color);
  dc.SetPixel(point.x + 3, point.y + 1, color);
  dc.SetPixel(point.x + 3, point.y + 2, color);
  dc.SetPixel(point.x + 3, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 4, color);
  dc.SetPixel(point.x + 3, point.y + 5, color);
  dc.SetPixel(point.x + 3, point.y + 6, color);
  dc.SetPixel(point.x + 4, point.y + 1, color);
  dc.SetPixel(point.x + 4, point.y + 2, color);
  dc.SetPixel(point.x + 4, point.y + 3, color);
  dc.SetPixel(point.x + 4, point.y + 4, color);
  dc.SetPixel(point.x + 4, point.y + 5, color);
  dc.SetPixel(point.x + 5, point.y + 2, color);
  dc.SetPixel(point.x + 5, point.y + 3, color);
  dc.SetPixel(point.x + 5, point.y + 4, color);
  dc.SetPixel(point.x + 6, point.y + 3, color);
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 --------
    // 4 ------x-
    // 5 -----x--
    // 6 ----x---
    // 7 ---x----
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 3, point.y + 7, clr);
    dc.SetPixel(point.x + 4, point.y + 6, clr);
    dc.SetPixel(point.x + 5, point.y + 5, clr);
    dc.SetPixel(point.x + 6, point.y + 4, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 ---x----
///  1 ---xx---
///  2 ---xxx--
///  3 xxxxxxx-
///  4 ---xxx--
///  5 ---xx---
///  6 ---x----
///  7 --------
/// \endcode
void
TDrawMenuItem::PaintCheck_Arrow(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+4,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+4,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 ---x----
  // 1 ---xx---
  // 2 ---xxx--
  // 3 xxxxxxx-
  // 4 ---xxx--
  // 5 ---xx---
  // 6 ---x----
  // 7 --------
  //
 
  dc.SetPixel(point.x + 0, point.y + 3, color);
  dc.SetPixel(point.x + 1, point.y + 3, color);
  dc.SetPixel(point.x + 2, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 0, color);
  dc.SetPixel(point.x + 3, point.y + 1, color);
  dc.SetPixel(point.x + 3, point.y + 2, color);
  dc.SetPixel(point.x + 3, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 4, color);
  dc.SetPixel(point.x + 3, point.y + 5, color);
  dc.SetPixel(point.x + 3, point.y + 6, color);
  dc.SetPixel(point.x + 4, point.y + 1, color);
  dc.SetPixel(point.x + 4, point.y + 2, color);
  dc.SetPixel(point.x + 4, point.y + 3, color);
  dc.SetPixel(point.x + 4, point.y + 4, color);
  dc.SetPixel(point.x + 4, point.y + 5, color);
  dc.SetPixel(point.x + 5, point.y + 2, color);
  dc.SetPixel(point.x + 5, point.y + 3, color);
  dc.SetPixel(point.x + 5, point.y + 4, color);
  dc.SetPixel(point.x + 6, point.y + 3, color);
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 --------
    // 4 ------x-
    // 5 -----x--
    // 6 ----x---
    // 7 ---x----
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 3, point.y + 7, clr);
    dc.SetPixel(point.x + 4, point.y + 6, clr);
    dc.SetPixel(point.x + 5, point.y + 5, clr);
    dc.SetPixel(point.x + 6, point.y + 4, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  1 -xxxxxxx
///  2 -xxxxxxx
///  3 -xxxxxxx
///  4 -xxxxxxx
///  5 -xxxxxxx
///  6 -xxxxxxx
///  7 -xxxxxxx
/// \endcode
//
void
TDrawMenuItem::PaintCheck_Box(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+4,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+4,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 --------
  // 1 -xxxxxxx
  // 2 -xxxxxxx
  // 3 -xxxxxxx
  // 4 -xxxxxxx
  // 5 -xxxxxxx
  // 6 -xxxxxxx
  // 7 -xxxxxxx
  //
 
  dc.TextRect(point.x + 1, point.y + 1, point.x + 7, point.y + 7, color);
 
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------x
    // 3 --------x
    // 4 --------x
    // 5 --------x
    // 6 --------x
    // 7 --------x
    //     xxxxxxx
    //
    TPen pen(TColor::Sys3dHilight, 0, PS_SOLID);
    dc.SelectObject(pen);
    dc.MoveTo(point.x + 2, point.y + 8);
    dc.LineTo(point.x + 8, point.y + 8);
    dc.MoveTo(point.x + 8, point.y + 2);
    dc.LineTo(point.x + 8, point.y + 9);
    dc.RestorePen();
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 --------
///  1 ----x---
///  2 ---xxx--
///  3 --xxxxx-
///  4 -xxxxxxx
///  5 --xxxxx-
///  6 ---xxx--
///  7 ----x---
/// \endcode
void
TDrawMenuItem::PaintCheck_Diamond(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+3,rect.top+2);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+3,rect.top+1);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 --------
  // 1 ----x---
  // 2 ---xxx--
  // 3 --xxxxx-
  // 4 -xxxxxxx
  // 5 --xxxxx-
  // 6 ---xxx--
  // 7 ----x---
  //
 
  dc.SetPixel(point.x + 1, point.y + 4, color);
  dc.SetPixel(point.x + 2, point.y + 3, color);
  dc.SetPixel(point.x + 2, point.y + 4, color);
  dc.SetPixel(point.x + 2, point.y + 5, color);
  dc.SetPixel(point.x + 3, point.y + 2, color);
  dc.SetPixel(point.x + 3, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 4, color);
  dc.SetPixel(point.x + 3, point.y + 5, color);
  dc.SetPixel(point.x + 3, point.y + 6, color);
  dc.SetPixel(point.x + 4, point.y + 1, color);
  dc.SetPixel(point.x + 4, point.y + 2, color);
  dc.SetPixel(point.x + 4, point.y + 3, color);
  dc.SetPixel(point.x + 4, point.y + 4, color);
  dc.SetPixel(point.x + 4, point.y + 5, color);
  dc.SetPixel(point.x + 4, point.y + 6, color);
  dc.SetPixel(point.x + 4, point.y + 7, color);
  dc.SetPixel(point.x + 5, point.y + 2, color);
  dc.SetPixel(point.x + 5, point.y + 3, color);
  dc.SetPixel(point.x + 5, point.y + 4, color);
  dc.SetPixel(point.x + 5, point.y + 5, color);
  dc.SetPixel(point.x + 5, point.y + 6, color);
  dc.SetPixel(point.x + 6, point.y + 3, color);
  dc.SetPixel(point.x + 6, point.y + 4, color);
  dc.SetPixel(point.x + 6, point.y + 5, color);
  dc.SetPixel(point.x + 7, point.y + 4, color);
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 --------
    // 4 --------
    // 5 -------x
    // 6 ------x-
    // 7 -----x--
    //       x
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 4, point.y + 8, clr);
    dc.SetPixel(point.x + 5, point.y + 7, clr);
    dc.SetPixel(point.x + 6, point.y + 6, clr);
    dc.SetPixel(point.x + 7, point.y + 5, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 ---xx---
///  1 --xxxx--
///  2 -xxxxxx-
///  3 -xxxxxx-
///  4 -xxxxxx-
///  5 --xxxx--
///  6 ---xx---
///  7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_Dot(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+4,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+4,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 ---xx---
  // 1 --xxxx--
  // 2 -xxxxxx-
  // 3 -xxxxxx-
  // 4 -xxxxxx-
  // 5 --xxxx--
  // 6 ---xx---
  // 7 --------
  //
 
  TPen pen(color, 0, PS_SOLID);
  dc.SelectObject(pen);
 
  dc.MoveTo(point.x + 1, point.y + 2);
  dc.LineTo(point.x + 1, point.y + 5);
  dc.MoveTo(point.x + 2, point.y + 1);
  dc.LineTo(point.x + 2, point.y + 6);
  dc.MoveTo(point.x + 3, point.y + 0);
  dc.LineTo(point.x + 3, point.y + 7);
  dc.MoveTo(point.x + 4, point.y + 0);
  dc.LineTo(point.x + 4, point.y + 7);
  dc.MoveTo(point.x + 5, point.y + 1);
  dc.LineTo(point.x + 5, point.y + 6);
  dc.MoveTo(point.x + 6, point.y + 2);
  dc.LineTo(point.x + 6, point.y + 5);
  dc.RestorePen();
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 --------
    // 4 --------
    // 5 ------x-
    // 6 -----x--
    // 7 ---xx---
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 3, point.y + 7, clr);
    dc.SetPixel(point.x + 4, point.y + 7, clr);
    dc.SetPixel(point.x + 5, point.y + 6, clr);
    dc.SetPixel(point.x + 6, point.y + 5, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 --------
///  1 --------
///  2 --------
///  3 --------
///  4 --------
///  5 --------
///  6 --------
///  7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_None(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  rect.Inflate(-2,-2);
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 --------
  // 1 --------
  // 2 --------
  // 3 --------
  // 4 --------
  // 5 --------
  // 6 --------
  // 7 --------
  //
}
//
///   Draw this:
/// \code
///    01234567
///  0 --------
///  1 ---xx---
///  2 ---xx---
///  3 -xxxxxx-
///  4 -xxxxxx-
///  5 ---xx---
///  6 ---xx---
///  7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_Plus(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+4,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+4,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 --------
  // 1 ---xx---
  // 2 ---xx---
  // 3 -xxxxxx-
  // 4 -xxxxxx-
  // 5 ---xx---
  // 6 ---xx---
  // 7 --------
  //
 
  TPen Pen(color, 0, PS_SOLID);
  dc.SelectObject(Pen);
 
  dc.MoveTo(point.x + 3, point.y + 1);
  dc.LineTo(point.x + 3, point.y + 7);
  dc.MoveTo(point.x + 4, point.y + 1);
  dc.LineTo(point.x + 4, point.y + 7);
  dc.MoveTo(point.x + 1, point.y + 3);
  dc.LineTo(point.x + 7, point.y + 3);
  dc.MoveTo(point.x + 1, point.y + 4);
  dc.LineTo(point.x + 7, point.y + 4);
  dc.RestorePen();
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 --------
    // 4 --------
    // 5 -----xx-
    // 6 -----x--
    // 7 ---xxx--
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 3, point.y + 7, clr);
    dc.SetPixel(point.x + 4, point.y + 7, clr);
    dc.SetPixel(point.x + 5, point.y + 7, clr);
    dc.SetPixel(point.x + 5, point.y + 6, clr);
    dc.SetPixel(point.x + 5, point.y + 5, clr);
    dc.SetPixel(point.x + 6, point.y + 5, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 ------x-
///  1 -----xx-
///  2 x---xxx-
///  3 xx-xxx--
///  4 xxxxx---
///  5 -xxx----
///  6 --x-----
///  7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_V(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  //TPoint point(rect.left+4,rect.top+3);
  rect.Inflate(-2,-2);
  TPoint point(rect.left+4,rect.top+2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 ------x-
  // 1 -----xx-
  // 2 x---xxx-
  // 3 xx-xxx--
  // 4 xxxxx---
  // 5 -xxx----
  // 6 --x-----
  // 7 --------
  //
 
  dc.SetPixel(point.x + 0, point.y + 2, color);
  dc.SetPixel(point.x + 0, point.y + 3, color);
  dc.SetPixel(point.x + 0, point.y + 4, color);
  dc.SetPixel(point.x + 1, point.y + 3, color);
  dc.SetPixel(point.x + 1, point.y + 4, color);
  dc.SetPixel(point.x + 1, point.y + 5, color);
  dc.SetPixel(point.x + 2, point.y + 4, color);
  dc.SetPixel(point.x + 2, point.y + 5, color);
  dc.SetPixel(point.x + 2, point.y + 6, color);
  dc.SetPixel(point.x + 3, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 4, color);
  dc.SetPixel(point.x + 3, point.y + 5, color);
  dc.SetPixel(point.x + 4, point.y + 2, color);
  dc.SetPixel(point.x + 4, point.y + 3, color);
  dc.SetPixel(point.x + 4, point.y + 4, color);
  dc.SetPixel(point.x + 5, point.y + 1, color);
  dc.SetPixel(point.x + 5, point.y + 2, color);
  dc.SetPixel(point.x + 5, point.y + 3, color);
  dc.SetPixel(point.x + 6, point.y + 0, color);
  dc.SetPixel(point.x + 6, point.y + 1, color);
  dc.SetPixel(point.x + 6, point.y + 2, color);
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 --------
    // 3 ------x-
    // 4 -----x--
    // 5 ----x---
    // 6 ---x----
    // 7 --x-----
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 2, point.y + 7, clr);
    dc.SetPixel(point.x + 3, point.y + 6, clr);
    dc.SetPixel(point.x + 4, point.y + 5, clr);
    dc.SetPixel(point.x + 5, point.y + 4, clr);
    dc.SetPixel(point.x + 6, point.y + 3, clr);
  }
}
//
///   Draw this:
/// \code
///    01234567
///  0 --------
///  1 xx---xx-
///  2 -xx-xx--
///  3 --xx----
///  4 ---xx---
///  5 -xx-xx--
///  6 xx---xx-
///  7 --------
/// \endcode
//
void
TDrawMenuItem::PaintCheck_X(TDC& dc, TRect& rect)
{
  //rect.Inflate(-3,-3);
  rect.Inflate(-2,-2);
  TColor color = SelectColor(IsEnabled());
 
  PaintCheckFace(dc,rect);
 
  //  Draw this:
  //
  //   01234567
  // 0 --------
  // 1 xx---xx-
  // 2 -xx-xx--
  // 3 --xx----
  // 4 ---xx---
  // 5 -xx-xx--
  // 6 xx---xx-
  // 7 --------
  //
  //TPoint point(rect.left+4,rect.top+3);
  TPoint point(rect.left+4,rect.top+2);
  dc.SetPixel(point.x + 0, point.y + 1, color);
  dc.SetPixel(point.x + 1, point.y + 1, color);
  dc.SetPixel(point.x + 1, point.y + 2, color);
  dc.SetPixel(point.x + 2, point.y + 2, color);
  dc.SetPixel(point.x + 2, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 3, color);
  dc.SetPixel(point.x + 3, point.y + 4, color);
  dc.SetPixel(point.x + 4, point.y + 4, color);
  dc.SetPixel(point.x + 4, point.y + 5, color);
  dc.SetPixel(point.x + 5, point.y + 5, color);
  dc.SetPixel(point.x + 5, point.y + 6, color);
  dc.SetPixel(point.x + 6, point.y + 6, color);
  dc.SetPixel(point.x + 5, point.y + 1, color);
  dc.SetPixel(point.x + 6, point.y + 1, color);
  dc.SetPixel(point.x + 4, point.y + 2, color);
  dc.SetPixel(point.x + 5, point.y + 2, color);
  dc.SetPixel(point.x + 1, point.y + 5, color);
  dc.SetPixel(point.x + 2, point.y + 5, color);
  dc.SetPixel(point.x + 0, point.y + 6, color);
  dc.SetPixel(point.x + 1, point.y + 6, color);
  if(!IsEnabled()){
    //  Add this:
    //
    //   01234567
    // 0 --------
    // 1 --------
    // 2 ------x-
    // 3 ----x---
    // 4 --------
    // 5 ---x----
    // 6 --x-----
    // 7 -x------
    //
    TColor clr = TColor::Sys3dHilight;
    dc.SetPixel(point.x + 6, point.y + 2, clr);
    dc.SetPixel(point.x + 4, point.y + 3, clr);
    dc.SetPixel(point.x + 3, point.y + 5, clr);
    dc.SetPixel(point.x + 2, point.y + 6, clr);
    dc.SetPixel(point.x + 1, point.y + 7, clr);
  }
}
 
//-------------------------------------------------------------------------
//
// class TDrawMenuItemProxy
// ~~~~~ ~~~~~~~~~~~~~~~~~~
//
/// Creates a font for use in menu bars.
//
TFont*
TDrawMenuItemProxy::CreateProxyMenuFont()
{
  NONCLIENTMETRICS ncm;
  ncm.cbSize = sizeof(NONCLIENTMETRICS);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
  return new TFont(ncm.lfMenuFont);
}
//
/// Constructs a TDrawMenuItemProxy object using the specified resource.
//
TDrawMenuItemProxy::TDrawMenuItemProxy(TResId resId, TModule* module)
:
 TDrawItemProxy(CreateProxyMenuFont())
{
  Array = new TUIntAray;
  TToolbarRes barRes(*module, resId, NoAutoDelete);
  int numRows = barRes.GetBitmap().Height()/barRes.GetHeight();
  { // map colors
    TBtnBitmap bitmap(barRes.GetBitmap(), TColor::LtGray, NoAutoDelete);
  }
 
  TCelArray* celAray = new TCelArray(
    &barRes.GetBitmap(),
    barRes.GetCount(),
    TSize(barRes.GetWidth(), barRes.GetHeight()),
    TPoint(0, 0), // offset
    numRows);
  SetCelArray(celAray);
 
  for(int i = 0; i < (int)barRes.GetCount(); i++){
    if(barRes.GetIds()[i] >0)
      Array->Add((uint)barRes.GetIds()[i]);
  }
}
//
/// Destroys the instance.
//
TDrawMenuItemProxy::~TDrawMenuItemProxy()
{
  delete Array;
}
//
/// Returns the item with id cmdId if it exists; otherwise creates a new item and
/// returns it.
//
TDrawItem*
TDrawMenuItemProxy::CreateItem(uint cmdId, const tstring& text)
{
  TDrawItemArray& items = GetItems();
  int index = GetIndex((int)cmdId);
 
  // if item already exist -> return existing one
  for(int i = 0; i < (int)items.Size(); i++){
    TButtonTextDrawItem* item = TYPESAFE_DOWNCAST(items[i], TButtonTextDrawItem);
    if(item->GetIndex() == index && item->GetText() == text)
      return items[i];
  }
  if(cmdId == static_cast<uint>(TButtonTextDrawItem::sepNoBitmap)) //JJH added static_cast
    index = TButtonTextDrawItem::sepNoBitmap;
 
  // if none found -> add new one
  TDrawMenuItem* item = new TDrawMenuItem(this, cmdId, index, text);
  RegisterItem(item);
 
  return item;
}
//
/// Walks through the menu tree hMenu adding seperators.
//
void
TDrawMenuItemProxy::RemapMenu(HMENU hMenu)
{
  iRecurse = 0; // this->iRecurse = 0;
 
  iRecurse++;
  int nItem = ::GetMenuItemCount(hMenu);
  while ((--nItem)>=0) {
    uint itemId = ::GetMenuItemID(hMenu, nItem);
    if (itemId == (uint) -1){
      HMENU pops = ::GetSubMenu(hMenu, nItem);
      if (pops)
        RemapMenu(pops);
      if (iRecurse>0){
        tchar buffer[MAX_PATH];
        if (::GetMenuString(hMenu, nItem, buffer, MAX_PATH, MF_BYPOSITION) > 0){
          TDrawItem* item = CreateItem((uint)TButtonTextDrawItem::sepNoBitmap, buffer); // itemId = -1
          ::ModifyMenu(hMenu, nItem, MF_BYPOSITION|MF_OWNERDRAW, (uint)-1, (LPCTSTR)item);
        }
      }
    }
    else {
      uint oldState = ::GetMenuState(hMenu, nItem, MF_BYPOSITION);
      if (!(oldState&MF_OWNERDRAW) && !(oldState&MF_BITMAP))  {
        if ((oldState&MF_SEPARATOR) || itemId == 0){
          // Insert separator items only if a background bitmap is drawn
          //
        }
        else{
          tchar buffer[MAX_PATH];
          if (::GetMenuString(hMenu, nItem, buffer, MAX_PATH, MF_BYPOSITION) > 0){
            TDrawItem* item = CreateItem(itemId, buffer);
            ::ModifyMenu(hMenu, nItem, MF_BYPOSITION|MF_OWNERDRAW|oldState,
               (LPARAM)itemId, (LPCTSTR)item);
          }
        }
      }
    }
  }
  iRecurse--;
}
//
/// Returns true if a shortcut was pressed that fits into the menu and false if not.
//
bool
TDrawMenuItemProxy::EvMenuChar(uint uChar, uint, HMENU hMenu, TParam2& param)
{
  PRECONDITION(hMenu);
  tchar keyPressed = (tchar)_totupper(uChar);
  int count = ::GetMenuItemCount(hMenu);
  while(count >= 0){
    uint itemId = ::GetMenuItemID(hMenu, count);
    if(itemId){
      TMenuItemInfo itemInfo(MIIM_DATA | MIIM_TYPE);
      if(::GetMenuItemInfo(hMenu, count, true, &itemInfo)){
        if(itemInfo.fType & MFT_OWNERDRAW){
          TDrawMenuItem* item = 0;
          try{
            item = TYPESAFE_DOWNCAST((TDrawMenuItem*)itemInfo.dwItemData,TDrawMenuItem);
          }
          catch(...){
            //.........
          }
          if(item){
            const tchar* p = _tcschr(item->GetText(),_T('&'));
            if(p){
              p++;
              if(_totupper(*p) == keyPressed){
                // Shortcut found.
                param = MkUint32((uint16)count, 2);
                return true;
              }
            }
          }
        }
      }
    }
    count--;
  }
  // Shortcut not found.
  return false;
}
//
/// Returns the TDrawItem with id cmdId, or 0 if it doesn't exist.
//
TDrawItem* TDrawMenuItemProxy::FindItem(uint cmdId)
{
  TDrawItemArray& items = GetItems();
  auto index = GetIndex(cmdId);
  if (index != items.NPOS)
    return items[index];
 
  const auto n = static_cast<int>(items.Size());
  for (index = 0; index != n; ++index)
  {
    const auto m = dynamic_cast<TDrawMenuItem*>(items[index]);
    if (m && m->GetCmdId() == static_cast<int>(cmdId))
      break;
  }
  return index < n ? items[index] : nullptr;
}
//
/// Returns the array index of the item with id cmdId.
//
int TDrawMenuItemProxy::GetIndex(int cmdId)
{
  return Array->Find(cmdId);
}
//
} // OWL namespace
 
////////////////////////////////////////////////////////////////////////////////
 
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: iRecurse.

V1037 Two or more case-branches perform the same actions. Check lines: 376, 379, 382

V1037 Two or more case-branches perform the same actions. Check lines: 607, 610, 613

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

V768 The variable 'edge' is of enum type. It is odd that it is used as a variable of a Boolean-type.

V525 The code contains the collection of similar blocks. Check items '2', '8', '8', '8' in lines 897, 898, 899, 900.

V525 The code contains the collection of similar blocks. Check items '7', '7', '7', '6', '5', '5' in lines 1160, 1161, 1162, 1163, 1164, 1165.

V565 An empty exception handler. Silent suppression of exceptions can hide the presence of bugs in source code during testing.

V817 It is more efficient to seek '\t' character rather than a string.

V817 It is more efficient to seek '\x08' character rather than a string.