//------------------------------------------------------------------------------
// OWL Extensions (OWLEXT) Class Library
// POPEDIT.CPP
//
// TPopupButton Class
// TPopupEdit Class
//
// Original code by Daniel BERMAN (dberman@inge-com.fr)
// Written: 15th November 1995
//
//------------------------------------------------------------------------------
#include <owlext\pch.h>
#pragma hdrstop
 
#include <owl/button.h>
#include <owl/celarray.h>
 
#include <owlext/popedit.h>
 
using namespace owl;
 
namespace OwlExt {
 
// private function
TModule* FindResourceModule(TWindow* parent, TModule* module, TResId resId, LPCTSTR type);
 
class TPopupButton : public TButton {
public:
  enum {Up, Down, Disabled};
 
  TPopupButton(TWindow *parent, TPopupEdit* edit, TResId bmpId, TModule* module);
  ~TPopupButton();
 
  void      BuildBmpArray();
  auto GetWindowClassName() -> owl::TWindowClassName override;
  void      Layout(int bSizeEditBox = true);
  void SetupWindow() override;
 
  void      EvClicked();
  void      EvDrawItem(uint ctrlId, const DRAWITEMSTRUCT& drawInfo);
  void      EvMouseMove(uint modKeys, const TPoint& point);
  void      EvSysColorChange();
 
protected:
  TResId       BmpId;
  TCelArray*   BmpArray;
  TPopupEdit* PopupEdit;
 
  DECLARE_RESPONSE_TABLE(TPopupButton);
};
 
 
//
//-- TPopupButton --------------------------------------------------------------
//
 
DEFINE_RESPONSE_TABLE1(TPopupButton, TButton)
EV_WM_DRAWITEM,
EV_WM_MOUSEMOVE,
EV_WM_SYSCOLORCHANGE,
EV_NOTIFY_AT_CHILD(BN_CLICKED, EvClicked),
END_RESPONSE_TABLE;
 
TPopupButton::TPopupButton(TWindow *parent, TPopupEdit* edit, TResId bmpId,
               TModule* module)
               :
TButton(parent, 0, _T(""), 0, 0, 0, 0, false, module)
{
  ModifyStyle(WS_TABSTOP,BS_OWNERDRAW);
 
  BmpId = bmpId;
  BmpArray = 0;
  PopupEdit = edit;
 
  BuildBmpArray();
 
  if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow))
    PopupEdit->GetWindowAttr().H = BmpArray->CelSize().cy;
}
 
TPopupButton::~TPopupButton()
{
  delete BmpArray;
}
 
void TPopupButton::BuildBmpArray()
{
  TBitmap bmp(*FindResourceModule(Parent, GetModule(),BmpId,RT_BITMAP), BmpId);
  int bmpWidth = bmp.Width();
  int bmpHeight = bmp.Height() / 2;
 
  TBrush faceBrush(TColor::Sys3dFace);
  TBrush hiliteBrush(TColor::Sys3dHilight);
  TBrush shadowBrush(TColor::Sys3dShadow);
  TBrush frameBrush(TColor::SysWindowFrame);
 
  if (!BmpArray){
    int width = (bmpWidth + 4) * 3;
    int height = bmpHeight + 4;
    TBitmap* tmp = new TBitmap(TScreenDC(), width, height);
    BmpArray = new TCelArray(tmp, 3);
  }
 
  TMemoryDC bmpDC;
  {
    TBitmap tmp(TScreenDC(), bmpWidth, bmpHeight);
    bmpDC.SelectObject(tmp);
    bmpDC.FillRect(0, 0, bmpWidth, bmpHeight, faceBrush);
    DrawMaskedBmp(bmpDC, 0, 0, bmp, 0, bmpWidth);
  }
 
  TMemoryDC memDC;
  memDC.SelectObject(*BmpArray);
 
  TRect bmpRect = BmpArray->CelRect(Up);
  memDC.FrameRect( bmpRect, frameBrush ) ;
  bmpRect.Inflate(-1, -1);
  memDC.SelectObject(hiliteBrush);
  memDC.PatBlt(bmpRect.left, 1, bmpRect.Width(), 1, PATCOPY);
  memDC.PatBlt(bmpRect.left, bmpRect.top, 1, bmpRect.Height(), PATCOPY);
  memDC.SelectObject(shadowBrush);
  memDC.PatBlt(bmpRect.right - 1, 1, 1, bmpRect.Height(), PATCOPY);
  memDC.PatBlt(bmpRect.left, bmpRect.Height(), bmpRect.Width(), 1, PATCOPY);
  memDC.BitBlt(BmpArray->CelRect(Up).OffsetBy(2, 2), bmpDC, TPoint(0, 0));
 
  bmpRect = BmpArray->CelRect(Down);
  memDC.FrameRect( bmpRect, frameBrush ) ;
  bmpRect.Inflate(-1, -1);
  memDC.FillRect(bmpRect, faceBrush);
  memDC.SelectObject(shadowBrush);
  memDC.PatBlt(bmpRect.left, 1, bmpRect.Width(), 1, PATCOPY);
  memDC.PatBlt(bmpRect.left, bmpRect.top, 1, bmpRect.Height(), PATCOPY);
  memDC.BitBlt(BmpArray->CelRect(Down).OffsetBy(3, 3), bmpDC, TPoint(0, 0));
 
  bmpRect = BmpArray->CelRect(Disabled);
  memDC.FrameRect( bmpRect, frameBrush ) ;
  bmpRect.Inflate(-1, -1);
  memDC.FillRect(bmpRect, faceBrush);
  memDC.BitBlt(BmpArray->CelRect(Disabled).OffsetBy(2, 2), bmpDC, TPoint(0, 0));
  memDC.BitBlt(BmpArray->CelRect(Disabled).OffsetBy(2, 2), bmpDC, TPoint(0, 0), 0x00B8074AL);
  memDC.SelectObject(hiliteBrush);
  memDC.PatBlt(bmpRect.left, 1, bmpRect.Width(), 1, PATCOPY);
  memDC.PatBlt(bmpRect.left, bmpRect.top, 1, bmpRect.Height(), PATCOPY);
  memDC.SelectObject(shadowBrush);
  memDC.PatBlt(bmpRect.right - 1, 1, 1, bmpRect.Height(), PATCOPY);
  memDC.PatBlt(bmpRect.left, bmpRect.Height(), bmpRect.Width(), 1, PATCOPY);
}
 
void TPopupButton::EvClicked()
{
  PopupEdit->Clicked();
}
 
void TPopupButton::EvDrawItem(uint /*ctrlId*/, const DRAWITEMSTRUCT& drawInfo)
{
  TRect bmpRect;
  if (drawInfo.itemState & ODS_SELECTED)
    bmpRect = BmpArray->CelRect(Down);
  else if (drawInfo.itemState & ODS_DISABLED)
    bmpRect = BmpArray->CelRect(Disabled);
  else
    bmpRect = BmpArray->CelRect(Up);
 
  TDC dc(drawInfo.hDC);
  TMemoryDC memDC(dc);
  memDC.SelectObject(*BmpArray);
  dc.BitBlt(0, 0, Attr.W, Attr.H, memDC, bmpRect.left, bmpRect.top);
}
 
void TPopupButton::EvMouseMove(uint modKeys, const TPoint& point)
{
  if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow) && !(modKeys & MK_LBUTTON))
    PopupEdit->SendMessage(WM_MOUSEMOVE, (WPARAM)modKeys, MAKELPARAM(0, 0));
  TButton::EvMouseMove(modKeys, point);
}
 
void TPopupButton::EvSysColorChange()
{
  BuildBmpArray();
  TButton::EvSysColorChange();
}
 
auto TPopupButton::GetWindowClassName() -> TWindowClassName
{
  return TWindowClassName{_T("BUTTON")};
}
 
void TPopupButton::Layout(int bSizeEditBox)
{
 
  TRect  rcEdit, rcParent, rcThis;
 
  PopupEdit->GetWindowRect(rcEdit);
  Parent->GetClientRect(rcParent);
  Parent->MapWindowPoints(NULL, rcParent, 2);
 
  if (bSizeEditBox)
    rcEdit.right -= BmpArray->CelSize().cx + 1;
 
  PopupEdit->SetWindowPos(NULL, rcEdit, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
 
  rcThis = rcEdit ;
  rcThis -= rcParent.TopLeft();
  rcThis.left = rcThis.right + 1;
  rcThis.right += BmpArray->CelSize().cx + 1;
 
  SetWindowPos(*PopupEdit, rcThis, SWP_NOACTIVATE);
 
}
 
void TPopupButton::SetupWindow()
{
  TButton::SetupWindow();
  EnableWindow(PopupEdit->IsWindowEnabled());
  Layout();
}
 
 
//
//-- TPopupEdit ----------------------------------------------------------------
//
 
DEFINE_RESPONSE_TABLE1(TPopupEdit, TEdit)
EV_WM_ENABLE,
EV_WM_KEYDOWN,
EV_WM_MOUSEMOVE,
EV_WM_SHOWWINDOW,
EV_WM_SIZE,
EV_WM_SYSKEYDOWN,
END_RESPONSE_TABLE;
 
TPopupEdit::TPopupEdit(TWindow* parent, int id, LPCTSTR text,
             int x, int y, int w, int h, TResId bmpId, uint textLen,
             TModule* module)
             :
TEdit(parent, id, text, x, y, w, h, textLen, false, module)
{
  Init(bmpId);
}
 
TPopupEdit::TPopupEdit(TWindow* parent, int resourceId, TResId bmpId,
             uint textLen, TModule* module)
             :
TEdit(parent, resourceId, textLen, module)
{
  Init(bmpId);
}
 
TPopupEdit::~TPopupEdit()
{
  delete Font;
}
 
void TPopupEdit::EvEnable(bool enabled)
{
  PopupBtn->EnableWindow(enabled);
}
 
void TPopupEdit::EvKeyDown(uint key, uint repeatCount, uint flags)
{
  switch (key){
case VK_DOWN:
  Clicked();
  break;
default:
  TEdit::EvKeyDown(key, repeatCount, flags);
  }
}
 
void TPopupEdit::EvMouseMove(uint modKeys, const TPoint& point)
{
  if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow)){
    TPoint p(point);
    MapWindowPoints(*Parent, &p, 1);
    Parent->SendMessage(WM_MOUSEMOVE, (WPARAM)modKeys, MAKELPARAM(p.x, p.y));
  }
  else
    TEdit::EvMouseMove(modKeys, point);
}
 
void TPopupEdit::EvShowWindow(bool show, uint status)
{
  TEdit::EvShowWindow(show, status);
  if (*PopupBtn)
    PopupBtn->ShowWindow(show ? SW_SHOW : SW_HIDE);
}
 
void TPopupEdit::EvSize(uint /*sizeType*/, const TSize& /*size*/)
{
  static int bEvSize = false;
 
  if (!bEvSize){
    bEvSize = true;
    if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow))
      PopupBtn->Layout(false);
    DefaultProcessing();
    bEvSize = false;
  }
}
 
void TPopupEdit::EvSysKeyDown(uint key, uint repeatCount, uint flags)
{
  switch (key){
case VK_DOWN:
  if (flags & KF_ALTDOWN){
    Clicked();
    break;
  }
default:
  TEdit::EvSysKeyDown(key, repeatCount, flags);
  }
}
 
void TPopupEdit::Init(TResId bmpId)
{
  Font = 0;
  PopupBtn = new TPopupButton(Parent, this, bmpId, GetModule());
}
 
void TPopupEdit::SetupWindow()
{
  TEdit::SetupWindow();
 
  if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow)){
    Font = new TFont(_T("MS Shell Dlg"), -8);
    SetWindowFont(*Font, false);
  }
}
 
void TPopupEdit::SysColorChange()
{
  HandleMessage(WM_SYSCOLORCHANGE);
  PopupBtn->HandleMessage(WM_SYSCOLORCHANGE);
}
 
 
//
//-- TToolBar ------------------------------------------------------------------
//
 
TToolBar::TToolBar(TWindow* parent, TTileDirection direction, TFont* font,
           TModule* module)
           :
TControlBar(parent, direction, font, module)
{
}
 
bool TToolBar::IdleAction(long idleCount)
{
  if (idleCount == 0){
    if (AtMouse){
      TPoint crsPoint;
      GetCursorPos(crsPoint);
      ScreenToClient(crsPoint);
      if (!GadgetFromPoint(crsPoint) && !ChildWindowFromPoint(crsPoint))
        HandleMessage(WM_MOUSEMOVE, 0, MAKELPARAM(-1, -1));
    }
 
    for (TGadget* g = Gadgets; g; g = g->NextGadget())
      g->CommandEnable();
  }
  return TWindow::IdleAction(idleCount);
}
 
//
//-- TPopupEditGadget ----------------------------------------------------------
//
 
TPopupEditGadget::TPopupEditGadget(TWindow& control, TBorderStyle border)
:
TControlGadget(control, border)
{
}
 
void TPopupEditGadget::MouseEnter(uint modKeys, const TPoint& pt)
{
  TControlGadget::MouseEnter(modKeys, pt);
  if (Window->GetHintMode() == TGadgetWindow::EnterHints)
    Window->SetHintCommand(GetId());
}
 
void TPopupEditGadget::MouseLeave(uint modKeys, const TPoint& pt)
{
  TControlGadget::MouseLeave(modKeys, pt);
  if (Window->GetHintMode() == TGadgetWindow::EnterHints)
    Window->SetHintCommand(-1);
}
 
void TPopupEditGadget::SysColorChange()
{
  TPopupEdit* p = TYPESAFE_DOWNCAST( Control, TPopupEdit ) ;
  if( p )
    p->SysColorChange();
}
 
 
//
//-- Miscellaneous functions ---------------------------------------------------
//
 
// DrawMaskedBitmap was developed by Steve Saxon (CIS: 100321,2355)
// and Russell Morris (CIS: 75627,3615).
bool DrawMaskedBmp(HDC hDC, int x, int y, HBITMAP hbm, int XOrigin, int nWidth)
{
  HDC hdcShadow, hdcSource;
  HBITMAP hbmpOld, hbmpOld2, hbmDraw;
  BITMAP bm;
  int nHeight;
  bool bReturn;
 
  if (hbm == NULL)
    return FALSE;
 
  GetObject(hbm, sizeof(bm), &bm);
 
  if (nWidth == 0)
    nWidth = bm.bmWidth - XOrigin;
 
  nHeight = bm.bmHeight >> 1;
 
  hbmDraw = CreateCompatibleBitmap(hDC, nWidth, nHeight);
 
  if (hbmDraw == NULL)
    return FALSE;
 
  hdcShadow = CreateCompatibleDC(hDC);
  hdcSource = CreateCompatibleDC(hDC);
 
  hbmpOld = (HBITMAP)SelectObject(hdcShadow, hbmDraw);
  hbmpOld2 = (HBITMAP)SelectObject(hdcSource, hbm);
 
  bReturn = BitBlt(hdcShadow, 0, 0, nWidth, nHeight, hDC, x, y, SRCCOPY);
 
  if (bReturn)
    bReturn = BitBlt(hdcShadow, 0, 0, nWidth, nHeight, hdcSource, XOrigin, nHeight, SRCAND);
 
  if (bReturn)
    bReturn = BitBlt(hdcShadow, 0, 0, nWidth, nHeight, hdcSource, XOrigin, 0, SRCPAINT);
 
  if (bReturn)
    bReturn = BitBlt(hDC, x, y, nWidth, nHeight, hdcShadow, 0, 0, SRCCOPY);
 
  SelectObject(hdcShadow, hbmpOld);
  SelectObject(hdcSource, hbmpOld2);
 
  DeleteDC(hdcShadow);
  DeleteDC(hdcSource);
 
  DeleteObject(hbmDraw);
 
  return bReturn;
}
 
} // OwlExt namespace
//==============================================================================

V601 The 'false' value is implicitly cast to the integer type.

V601 The 'true' value is implicitly cast to the integer type.

V601 The 'false' value is implicitly cast to the integer type. Inspect the first argument.

V601 The 'false' value is implicitly cast to the integer type.

V818 It is more efficient to use an initialization list 'BmpId(bmpId)' rather than an assignment operator.