//buttonx.cpp

#include <owl/pch.h>
#include <stdio.h>
#include "source/buttonx.h"
#include <math.h>

DEFINE_RESPONSE_TABLE1(TButtonEx, TGlyphDib)
  EV_WM_EXITMENULOOP,
  EV_WM_MOUSEMOVE,
  EV_WM_LBUTTONUP,
  EV_WM_LBUTTONDOWN,
  EV_WM_KEYDOWN,
  EV_WM_KEYUP,
END_RESPONSE_TABLE;
 

TButtonEx::TButtonEx(TWindow* parent, int id, constcharfar* text,
                          int X, int Y, int W, int H, bool isDefault,
                           TModule* module)
: TGlyphDib(parent, id, text,X,Y,W,H, isDefault,module)
{
  BX_InitVars();
}

TButtonEx::TButtonEx(TWindow* parent, int resourceId, TModule* module)
:TGlyphDib(parent, resourceId, module)
{
  BX_InitVars();
}

TButtonEx::~TButtonEx()
{
}

void TButtonEx::BX_InitVars()
{
  BX_ColorText=TColor::SysBtnText;
  BX_ColorTextNegative=TColor::SysBtnText;
  BX_ColorBk=TColor::Sys3dFace;
  BX_ColorBkNegative=TColor::Sys3dFace;

  BX_GadgetBorder=true;
  BX_ThinBorder=false;
  BX_Focus=false;
  BX_FlatAlways=false;
  BX_Flat=false;
  BX_TextOnGlyph=false;

  BX_Menu=0;

  MouseIsIn=false;
  WasPushed=false;
}

void TButtonEx::BX_SetCursor(int id)
{
  SetCursor(GetModule(),id);
}

void TButtonEx::BX_SetMenu(int id)
{
  BX_Menu=id;
}

void TButtonEx::PaintFace(TDC& dc, TRect& rect)
{
  // Fill the background with the face color
  TColor bkcolor=(MouseIsIn||IsSet(biPushed))?BX_ColorBkNegative:BX_ColorBk;
  TBrush brush(bkcolor);
  dc.FillRect(rect, brush);

  // Grab the glyph and it's size
  TDib* glyph = 0;            // Pointer to glyph
  TRect glyphRect(0, 0, 0, 0);   // Size of glyph
  if (IsSet(biShowGlyph))
  {
    glyph = dibOf(gtUp);
    if( ButtonDisabled() )      glyph = dibOf(gtDisabled);
    else if( ButtonFocus() )    glyph = dibOf(gtFocus);
    else if( ButtonDown() )      glyph = dibOf(gtDown);
    else if( ButtonNegative() ) glyph = dibOf(gtNegative);
    CHECK(glyph && glyph->IsGDIObject());
    glyphRect.Set(0, 0, glyph->Width(), glyph->Height());
  }

  // Grab some information about the text/caption
  int len = 0;                   // Length of Caption
  TRect textRect(0, 0, 0, 0);    // Size of text
  TAPointer<char> text;          // Pointer to caption dynamic buffer
  TPointer<TFont> tmpFnt;        // Object wrapping font handle
  TColor textColor;              // Color used for button's text

  if (IsSet(biShowText))
  {
    len = GetWindowTextLength();
    if (len)
    {
      if (!BtnFontOf())  //useless checks!
      {
        HFONT hFont = HFONT(::SendMessage(::GetParent(*this), WM_GETFONT,0, 0));
        if (!hFont)
          hFont = HFONT(GetStockObject(TSystem::Has3dUI() ? ANSI_VAR_FONT :SYSTEM_FONT));
        if (hFont)
          tmpFnt = new TFont(hFont);
      }
      if (BtnFontOf())
      {
        CHECK(BtnFont->IsGDIObject());
        dc.SelectObject(*BtnFontOf());
      }
      else if (tmpFnt)
      {
        CHECK(((TFont&)tmpFnt).IsGDIObject());
        dc.SelectObject((TFont&)tmpFnt);
      }

      text = new char[len+1];
      GetWindowText(text, len+1);
      textRect.Set(0, 0, rect.Width() - glyphRect.Width(), SHRT_MAX);

      if (IsSet(biDisabled))
      {
        textColor = TColor::SysGrayText;
        if ((textColor == TColor::Sys3dFace.GetValue()) ||
            (textColor == TColor::SysBtnText.GetValue())) {
          textColor = TColor::Sys3dShadow;
        }
      }
      else
      {
        if (MouseIsIn || IsSet(biPushed) )
          textColor = BX_ColorTextNegative;
        else
          textColor = BX_ColorText;
      }

      TColor oldColor = dc.SetTextColor(textColor);

      dc.DrawText(text, len, textRect, DT_WORDBREAK|DT_CALCRECT);
      dc.SetTextColor(oldColor);
    }
  }

  // If we have text and/or glyph, lay them out and paint them
  if (!textRect.IsNull() || !glyphRect.IsNull()) {

    if( (!textRect.IsNull()) & (BX_TextOnGlyph) )
    {
      int x1=(rect.Width()-glyphRect.Width())/2;
      int x2=(rect.Height()-glyphRect.Height())/2;
      glyphRect=TRect(TPoint( x1,x2 ), glyphRect.Size() );
      int dy=(rect.Height()-dc.GetTextExtent(text, strlen(text)).cy)/2;
      textRect.Set(rect.left,rect.top+dy,rect.right,rect.bottom-dy);
    }
    else
    {
      LayoutTextGlyph(rect, textRect, glyphRect);
    }

    // Offset things to the lower right if we're in down
    if (IsSet(biPushed)) {                       ////changed
      if (!glyphRect.IsNull() && ((glyph == dibOf(gtDown))|(glyph == dibOf(gtNegative) )) )
        glyphRect.Offset(1, 1);
      if (!textRect.IsNull())
        textRect.Offset(1, 1);
    }

    // Paint the components of the button
    if (!glyphRect.IsNull()) {
      PRECONDITION(glyph && glyph->IsGDIObject());
      if(IsSet(biDisabled))
      {
        TBitmap  bitmap(*glyph, &TPalette((HPALETTE)::GetStockObject(DEFAULT_PALETTE)));
        TUIFace uiFace(glyphRect, bitmap);
        uiFace.Paint(dc, TPoint(0, 0), IsSet(biDisabled)?TUIFace::Disabled:TUIFace::Normal, IsSet(biPushed));
      }
      else
      {
        dc.SetDIBitsToDevice(glyphRect,TPoint(0,0),*glyph);
      }
    }

    if (!textRect.IsNull()) {
      int mode = dc.SetBkMode(TRANSPARENT);
      TColor oldColor = dc.SetTextColor(textColor);
      if(BX_TextOnGlyph)
        dc.DrawText(text, len, textRect, DT_CENTER|DT_WORDBREAK);
      else
        dc.DrawText(text, len, textRect, DT_WORDBREAK);
 

      if(IsSet(biDisabled))
      {
        dc.SetTextColor(TColor::Sys3dHilight);
        if(BX_TextOnGlyph)
          dc.DrawText(text, len, textRect.OffsetBy(1,1), DT_CENTER|DT_WORDBREAK);
        else
          dc.DrawText(text, len, textRect.OffsetBy(1,1), DT_WORDBREAK);
      }

      dc.SetTextColor(oldColor);
      dc.SetBkMode(mode);
    }

  }

  // Paint the focus rect [if necessary]
  if (IsSet(biFocus))
    PaintFocusRect(dc, rect);

  // Restore font
  if (len && (BtnFontOf() || tmpFnt))
    dc.RestoreFont();

}

void TButtonEx::PaintFrame(TDC& dc, TRect& rect)
{

  if(BX_FlatAlways)         return; //no border
  if(BX_Flat & !MouseIsIn)  return; //no border - unless mouse is in

//I don't remmember what the hell I did here
  if(BX_ThinBorder)
  {
    if(IsSet(biPushed))
      ::DrawEdge(dc, (LPRECT)&rect,  BDR_SUNKENOUTER,BF_ADJUST|BF_RECT);
    else
      ::DrawEdge(dc, (LPRECT)&rect,  BDR_RAISEDINNER,BF_ADJUST|BF_RECT);
  }
  else if(BX_GadgetBorder)
  {
    if(IsSet(biPushed))
      ::DrawEdge(dc, (LPRECT)&rect, EDGE_SUNKEN  ,BF_ADJUST|BF_RECT);
    else
    {
      ::DrawEdge(dc, (LPRECT)&rect,  BDR_RAISEDINNER  ,BF_ADJUST|BF_RECT);
      ::DrawEdge(dc, (LPRECT)&rect,  BDR_RAISEDOUTER  ,BF_ADJUST|BF_BOTTOM|BF_BOTTOMRIGHT);
    }
  }
  else
  {
    TUIBorder::TStyle style;
    style=(IsSet(biPushed) ? TUIBorder::ButtonDn : TUIBorder::WndRaised  );
    TUIBorder uiBorder(rect,style,BX_ThinBorder?TUIBorder::Soft:0);
    uiBorder.Paint(dc);
    rect = uiBorder.GetClientRect();
  }
}

void TButtonEx::PaintFocusRect(TDC& dc, const TRect& faceRect)
{
  if(!BX_Focus) return;
  TGlyphDib::PaintFocusRect(dc, faceRect);
}

void TButtonEx::MouseEnter()
{
  if(MouseIsIn) return;
  SetCapture();
  MouseIsIn=true;
  Invalidate(true);
}

void TButtonEx::MouseLeave()
{
  WasPushed=false;
  if (GetCapture() == *this)  ReleaseCapture();
  if(!MouseIsIn) return;
  MouseIsIn=false;
  if(IsSet(biPushed))
    SendMessage(BM_SETSTATE, false);
  Invalidate(true);
}

void TButtonEx::EvMouseMove(uint modKeys, TPoint& point)
{
  //sometimes the user pushes the button, then drags it outside
  //then comes back in. If this sort of none-sense is in progress
  //then let the parent class deal with it.
  if(WasPushed)
  {
    TGlyphDib::EvMouseMove(modKeys, point);
    return;
  }

  bool hit=(GetClientRect().Contains(point));
  if(hit) MouseEnter();
  else    MouseLeave();
}

void TButtonEx::EvLButtonDown(uint msg, TPoint& point)
{
  TGlyphDib::EvLButtonDown(msg, point);
  SetCapture();
  MouseIsIn=true;
  WasPushed=true;
}

void TButtonEx::EvLButtonUp(uint, TPoint& point)
{
  if(  IsSet(biPushed) & (GetCapture()==*this) ){
    ReleaseCapture();
    if(!BX_Menu)// if there is no menu push the button back up
      SendMessage(BM_SETSTATE, false);
    TRect rect;
    GetClientRect(rect);
    if (rect.Contains(point))
      SendNotificationEx();
  }
  WasPushed=false;
  MouseLeave();
}

//helper function - if true, then PaintFace should use gtNegative
bool TButtonEx::ButtonNegative()
{
  return( (!IsSet(biPushed)) && dibOf(gtNegative) && MouseIsIn );
}

//helper function - if true, then PaintFace should use gtDown
bool TButtonEx::ButtonDown()
{
  return (IsSet(biPushed) && dibOf(gtDown));
}

//helper function - if true, then PaintFace should use gtDisabled
bool TButtonEx::ButtonDisabled()
{
  return (IsSet(biDisabled) && dibOf(gtDisabled));
}

//helper function - if true, then PaintFace should use gtFocus
bool TButtonEx::ButtonFocus()
{
  return((IsSet(biFocus)) && dibOf(gtFocus));
}

void TButtonEx::MapColors(TDib* dib, TGlyphType type)
{
//  dib->MapUIColors(TDib::MapFace|TDib::MapText|TDib::MapShadow|TDib::MapHighlight);
//  Normally the above statement would be enough to map the colors;
//  but in this case background color may be different
//  so you have to map LtGray to the actual background color
  dib->MapColor(TColor::Black, TColor::SysBtnText);
  dib->MapColor(TColor::Gray, TColor::Sys3dShadow);
  dib->MapColor(TColor::White, TColor::Sys3dHilight);

  //If we are setting up the negative image, map light gray to
  //BX_ColorBkNegative. This color may be different than
  //BX_ColorBk
  if((type==gtNegative)|(type==gtDown))
    dib->MapColor(TColor::LtGray, BX_ColorBkNegative);

  //map LtGray to the current background color
  else
    dib->MapColor(TColor::LtGray, BX_ColorBk);
}

void TButtonEx::SendNotificationEx()
{
  if(BX_Menu)
  {
    TPopupMenu popup;
    popup = TPopupMenu(GetModule()->LoadMenu(BX_Menu), AutoDelete);
    popup.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON|TPM_RIGHTBUTTON,GetWindowRect().BottomLeft(),0,Parent->HWindow);
    MouseLeave();
    SendMessage(BM_SETSTATE, false);
  }
  else
    TGlyphDib::SendNotificationEx();

  if (!IsSet(biFocus))
    SetFocus();
}

void TButtonEx::EvExitMenuLoop(bool)
{
  WasPushed=false;
  ReleaseCapture();
  MouseIsIn=false;
  SendMessage(BM_SETSTATE, false);
  Invalidate(true);
}

void TButtonEx::EvKeyUp(uint key, uint repeatCount, uint flags)
{
  if(!BX_Focus) return;
  TGlyphDib::EvKeyUp(key, repeatCount, flags);
}

void TButtonEx::EvKeyDown(uint key, uint repeatCount, uint flags)
{
  if(!BX_Focus) return;
  TGlyphDib::EvKeyDown(key, repeatCount, flags);
}

void TButtonEx::PaintButton(TDC& dc)
{
  TGlyphDib::PaintButton(dc);
}