//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "gui_scroll_h.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tgui_scroll_h_Form *gui_scroll_h_Form;
//---------------------------------------------------------------------------

#include "gui.h"
#include "ide_main.h"

__fastcall Tgui_scroll_h_Form::Tgui_scroll_h_Form(TComponent* Owner)
        : TForm(Owner)
{
  //[환경변수]
  //{
      //[2007.10.02.화][추가!!!]
      IDE_Get_Option(&_ide_option);

  //}

  //[form]
  //{
      //[고정크기]{----------------
      //높이는 고정 크기를 갖는다.
      this->Height  = 13;
      //}--------------------------

      this->Color  = clWhite;
  //}

  //[bmp]
  //{
      //실제 그림 영역을 생성한다.
      _bmp_ = new Graphics::TBitmap;

      //그림 영역 크기 설정.
      _bmp_->Width       = Screen->Width;
      _bmp_->Height      = this->Height ;

      //24bit bitmap 으로 지정한다.
      _bmp_->PixelFormat = pf24bit;
  //}

  //[환경변수]
  //{
      //기본 환경 설정을 한다.
      //필요에 따라 다시 설정된다.
      _body_size   = this->Width - 16;
      _design_size = _body_size;
      _max         = 100;
      _min         = 0;
      _position    = 0;

      _thumb_selected    = false;
      _arrow_left_downed   = false;
      _arrow_right_downed = false;
  //}

  //[EVENT 함수포인터 초기화]
  //{
      //외부에서 함수를 등록해서 사용하므로 NULL 로 초기화 한다.
      _EVENT_Scroll = NULL;

      //[2009.11.28.토][추가!!!]{---------------------------------------------------------------
      //<_EVENT_Scroll> 동작 함수가 재귀호출되는 것을 막아준다.
      //즉, 이 함수가 다 처리되기 전에 다시 처리되어 통신등의 경우 꼬이는 것을 막기 위한것이다.
      _EVENT_Scroll_Running = false;
      //}---------------------------------------------------------------------------------------
      
  //}

  //[컨트롤 그리기]
  //{
      //컨트롤을 그려서 모양을 만든다.
      _Shape();
  //}

  return;

}

__fastcall Tgui_scroll_h_Form::~Tgui_scroll_h_Form(void)
{
  //[2012.04.29.일][수정!!!]

  if(_bmp_ != NULL) { delete _bmp_; _bmp_ = NULL; }

}

//[서브클래싱]------------------------------------------------------------------

void __fastcall Tgui_scroll_h_Form::WndProc(Messages::TMessage  &Message)
{
  //[2006.12.12.화][생성!!!]{-----------------------------------------------------
  //TForm 의 경우는 바탕을 칠하고 OnPaint() 를 발생하게 되므로 실제 _Draw() 를
  //OnPaint() 에서 사용하는 경우는 크기가 변경되는 경우 바로 칠해지지 않아서
  //하얀색 바탕이 그대로 나오게 되어 보기 좋지 않게 된다.
  //따라서 TForm 자체의 바탕을 그리는 WM_ERASEBKGND 에서 바로 _Draw() 를 사용하여
  //그리고 OnPaint() 는 처리하지 않는다.
  //C++Builder 와 같이 완벽하게 처리되는 깜박임이 전혀 없는 화면을 만들수 있다.
  //}-----------------------------------------------------------------------------

  if(Message.Msg == WM_ERASEBKGND)
  {
    _Draw();

    //바로 죵료하지 않으면 WM_ERASEBKGND 메세지가 다음 TForm::WndProc(Message); 에서
    //다시 처리 되어 TForm->Color 로 칠해지게 되어 _Draw() 로 그린 것이 다 지워지므로
    //바로 종료한다.
    return;

  }

  //[기본처리]
  //{
      //기본 메세지는 반드시 처리 되어야 한다.
      TForm::WndProc(Message);
  //}

  return;

}

//------------------------------------------------------------------------------

void __fastcall Tgui_scroll_h_Form::_Shape_Left_Arrow(bool  pDOWN)
{
  //[2006.10.26.목][생성!!!]

  //[VAR]
  //{
      TRect  rect;
      int    x, y;
      int    color_back;
      int    color_arrow;
  //}

  //[down]
  //{
      if(pDOWN == true)
      {
        //눌린 상태이므로 "반전" 시킨다.
        color_back  = _ide_option->color_0;
        color_arrow = IDE_COLOR_2;

      }
      else
      {
        //기본상태로 만든다.
        color_back  = IDE_COLOR_2;
        color_arrow = _ide_option->color_0;

      }
  //}

  //[바탕색]
  //{
      //화살표 영역만 칠한다.
      rect       = _bmp_->Canvas->ClipRect;
      rect.Right = 8;

      _bmp_->Canvas->Brush->Color = color_back;
      _bmp_->Canvas->FillRect(rect);
  //}

  //[위삼각형]
  //{
      for(x = 0; x < 6; x++)
      {
        for(y = (6 - x); y <= (6 + x); y++)
        {
          BMP_Dot(_bmp_, x + 1, y, color_arrow);

        }

      }
  //}

  //[view]{------------------------
  //그린 것을 보여준다.
  //this->Canvas->Draw(0, 0, _bmp_);
  _Draw();
  //}------------------------------

  return ;

}

void __fastcall Tgui_scroll_h_Form::_Shape_Right_Arrow(bool  pDOWN)
{
  //[2006.10.26.목][생성!!!]

  //[VAR]
  //{
      TRect  rect;
      int    x, y;
      int    color_back;
      int    color_arrow;
  //}

  //[down]
  //{
      if(pDOWN == true)
      {
        //눌린 상태이므로 "반전" 시킨다.
        color_back  = _ide_option->color_0;
        color_arrow = IDE_COLOR_2;

      }
      else
      {
        //기본상태로 만든다.
        color_back  = IDE_COLOR_2;
        color_arrow = _ide_option->color_0;

      }
  //}

  //[바탕색]
  //{
      //위 화살표 영역 절반만 칠한다.
      rect       = _bmp_->Canvas->ClipRect;
      rect.Left  = this->Width - 8;
      rect.Right = this->Width;

      _bmp_->Canvas->Brush->Color = color_back;
      _bmp_->Canvas->FillRect(rect);
  //}

  //[아래삼각형]
  //{
      for(x = 0; x < 6; x++)
      {
        for(y = (6 - x); y <= (6 + x); y++)
        {
          BMP_Dot(_bmp_, this->Width - 2 - x, y, color_arrow);

        }

      }
  //}

  //[view]{-------------
  //그린 것을 보여준다.
  _Draw();
  //}-------------------

  return ;

}

void __fastcall Tgui_scroll_h_Form::_Shape_Body(void)
{
  //[2006.10.26.목][생성!!!]{---------
  //패턴 형식으로 막대를 만들어 준다.
  //}---------------------------------

  //[VAR]
  //{
      int    x, y;
      int    i;
  //}

  //[환경변수]
  //{
      _body_size = this->Width - 16;
  //}

  //[바탕 지우기]
  //{
      _body_rect = _bmp_->Canvas->ClipRect;

      _body_rect.Left  += 8;
      _body_rect.Right -= 8;

      _bmp_->Canvas->Pen->Color   = IDE_COLOR_2;
      _bmp_->Canvas->Brush->Color = IDE_COLOR_2;
      _bmp_->Canvas->FillRect(_body_rect);
  //}

  for(x = 0, i = 0; x < _body_size ; x++)
  {
    for(y = 4; y < 9; y++, i++)
    {
      if(i%2 == 0)
      {
        //테두리 색.
        BMP_Dot(_bmp_, x + 8, y, _ide_option->color_0);

      }
      else
      {
        //바탕 색.
        BMP_Dot(_bmp_, x + 8, y, IDE_COLOR_2);

      }
    }
  }

  return;

}

void __fastcall Tgui_scroll_h_Form::_Shape_Thumb(void)
{
  //[2006.10.26.목][생성!!!]{-----------------------------------
  //이동막대를 만들되 양끝에 1 pixel 의 공백을 둔다.
  //_thumb_rect 전용 rect 구조체를 사용한다.
  //이는 _thumb_rect 정보를 다른 곳에서 사용해야 하기 때문이다.
  //}-----------------------------------------------------------

  //[VAR]
  //{
      int    x, y;
      int    i;
  //}

  //[환경변수]
  //{
      if((_max - _min) == 0)
      {
        //이 경우는 다음의 공식들의 분모가 0 이 되므로 별도처리한다.
        _thumb_size  = _body_size;
        _scroll_size = 0;
        _move_size   = 0;

      }
      else
      {
        _thumb_size  = (_body_size * _design_size) / (_design_size + (_max - _min));
        _scroll_size = _body_size - _thumb_size;
        _move_size   = (_scroll_size * (_position - _min)) / (_max - _min);

      }
  //}

  //[thumb]
  //{
      _thumb_rect.Top    = 4;
      _thumb_rect.Bottom = _thumb_rect.Top + 5;
      _thumb_rect.Left   = 8 + _move_size;
      _thumb_rect.Right  = _thumb_rect.Left + _thumb_size;

      _bmp_->Canvas->Pen->Color   = _ide_option->color_0;
      _bmp_->Canvas->Brush->Color = _ide_option->color_0;
      _bmp_->Canvas->FillRect(_thumb_rect);
  //}

  //[thumb 양쪽 여백]
  //{
      //thumb 양쪽에 1 pixel 의 공백을 만든다.
      //이는 thumb 가 더 정확하게 보이게 하기 위한 것이다.
      _bmp_->Canvas->Pen->Color = IDE_COLOR_2;

      _bmp_->Canvas->MoveTo(_thumb_rect.Left - 1, _thumb_rect.Top);
      _bmp_->Canvas->LineTo(_thumb_rect.Left - 1, _thumb_rect.Bottom);

      _bmp_->Canvas->MoveTo(_thumb_rect.Right, _thumb_rect.Top);
      _bmp_->Canvas->LineTo(_thumb_rect.Right, _thumb_rect.Bottom);
 //}

  return;

}

void __fastcall Tgui_scroll_h_Form::_Shape(void)
{
  //[2006.10.26.목][생성!!!]

  //[모양]
  //{
      _Shape_Body();
      _Shape_Thumb();
      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);
  //}

  //[view]{-------------
  //그린 것을 보여준다.
  _Draw();
  //}-------------------

  return ;

}

void __fastcall Tgui_scroll_h_Form::_Top(int  pTOP)
{
  //[2006.10.28.토][생성!!!]

  this->Top = pTOP;

  return;

}

void __fastcall Tgui_scroll_h_Form::_Left(int  pLEFT)
{
  //[2006.10.28.토][생성!!!]

  this->Left = pLEFT;

  return;

}

void __fastcall Tgui_scroll_h_Form::_Width(int  pWIDTH)
{
  //[2006.10.28.토][생성!!!]

  this->Width = pWIDTH;

  //높이가 바뀌었으므로 다시 그려준다.
  _Shape();

  return ;

}

void __fastcall Tgui_scroll_h_Form::_Height(int  pHEIGHT)
{
  //[2006.10.28.토][생성!!!]

  this->Height = pHEIGHT;

  //높이가 바뀌었으므로 다시 그려준다.
  _Shape();

  return ;

}

void __fastcall Tgui_scroll_h_Form::_DesignSize(int  pDESIGNsize)
{
  //[2006.10.29.일][생성!!!]

  _design_size = pDESIGNsize;

  _Shape();

  return;

}

void __fastcall Tgui_scroll_h_Form::_Max(int  pMAX)
{
  //[2006.10.29.일][생성!!!]

  _max = pMAX;

  _Shape();

  return;

}

void __fastcall Tgui_scroll_h_Form::_Min(int  pMIN)
{
  //[2006.10.29.일][생성!!!]

  _min = pMIN;

  _Shape();

  return;

}

void __fastcall Tgui_scroll_h_Form::_Position(int  pPOSITION)
{
  //[2006.10.29.일][생성!!!]{----------------------------
  //min <= position <= max 의 범위를 초과 해서는 안된다.
  //}----------------------------------------------------

  if     ((_min <= pPOSITION) && (pPOSITION <= _max))
  {
    //계산한 값을 할당한다.
    _position = pPOSITION;

  }
  else if(pPOSITION < _min)
  {
    //scroll 범위를 min 쪽으로 넘은 경우는 min 값을 할당하여
    //thumb 가 scrollbar 영역을 넘어서 이동할수 없도록한다.
    _position = _min;

  }
  else if(pPOSITION > _max)
  {
    //scroll 범위를 max 쪽으로 넘은 경우는 max 값을 할당하여
    //thumb 가 scrollbar 영역을 넘어서 이동할수 없도록한다.
    _position = _max;

  }

  //[그리기]{-------------------------------------------------
  //_position 값이 수정되었으므로 scrollbar 를 다시 그려준다.
  _Shape();
  //}---------------------------------------------------------

  if(_EVENT_Scroll != NULL)
  {
    //[2009.11.28.토][중요수정!!]{------------------------------
    //현재 [동작함수] 가 사용중이하면 다시 재귀호출하지 않는다.
    if(_EVENT_Scroll_Running == true) return;
    //}---------------------------------------------------------

    //현재 [동작함수] 가 사용중임을 표시한다.
    _EVENT_Scroll_Running = true;
    //{
        _EVENT_Scroll();

    //}
    //[동작함수] 사용이 완료되었음을 표시한다.
    _EVENT_Scroll_Running = false;

  }       

  return;

}

void __fastcall Tgui_scroll_h_Form::_Draw(void)
{
  //[2006.10.31.화][생성!!!]

  BitBlt(this->Canvas->Handle, 0, 0,
         this->Width, this->Height,
         _bmp_->Canvas->Handle, 0, 0, SRCCOPY);

  return;

}    

//[EVENT]-----------------------------------------------------------------------

void __fastcall Tgui_scroll_h_Form::FormMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
  //[2006.11.01.수][생성!!!]{---------------------------------------
  //X 만 검사하여 [왼쪽/오른쪽] 중 어느 화살표가 눌렸는지 확인하고,
  //해당 화살표를 눌린것으로 표시한다.
  //}---------------------------------------------------------------

  if(Button == mbLeft)
  {
    if     ((0 <= X) && (X < 8))
    {
      //[위쪽]

      if(scroll_Timer->Enabled != true)
      {
        //_position 값을 수정하고 자동으로 다시 scrollbar 를 그려준다.
        _Position(--_position);

      }

      //타이머 동작 시작.
      scroll_Timer->Enabled = true;

      _arrow_left_downed   = true;
      _arrow_right_downed = false;

      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);

    }
    else if(((this->Width - 8) <= X) && (X < this->Width))
    {
      //[아래쪽]

      if(scroll_Timer->Enabled != true)
      {
        //_position 값을 수정하고 자동으로 다시 scrollbar 를 그려준다.
        _Position(++_position);

      }

      //타이머 동작 시작.
      scroll_Timer->Enabled = true;

      _arrow_left_downed   = false;
      _arrow_right_downed = true;

      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);

    }
    //thumb 영역인지 확인한다.
    //전용 rect 정보를 참고하여 처리한다.
    else if((_thumb_rect.Left <= X) && (X < _thumb_rect.Right))
    {
      //thumb 영역인 경우는 마우스로 집어끌기 위한 시작 좌표를 기록한다.
      _mouse_down_move_size = _move_size;
      _mouse_down_point.x   = X;

      //thumb 를 집어끈다는 것을 알려준다.
      _thumb_selected = true;

    }
  }

  //[2007.04.05.목][추가!!!]
  if(_EVENT_MouseDown != NULL)
  {
    _EVENT_MouseDown();

  }

  return;

}

void __fastcall Tgui_scroll_h_Form::FormMouseUp(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
  //[2006.11.01.수][생성!!!]

  if(Button == mbLeft)
  {
    if     ((0 <= X) && (X < 8))
    {
      //모두 해제.
      _arrow_left_downed   = false;
      _arrow_right_downed = false;

      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);

    }
    else if(((this->Width - 8) <= X) && (X < this->Width))
    {
      //모두 해제.
      _arrow_left_downed   = false;
      _arrow_right_downed = false;

      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);

    }
    else
    {
      //모두 해제.
      _arrow_left_downed   = false;
      _arrow_right_downed = false;

      _Shape_Left_Arrow(_arrow_left_downed);
      _Shape_Right_Arrow(_arrow_right_downed);

    }

  }

  //[해제]{-----------------------
  //thumb 집어 끌기를 해제한다.
  _thumb_selected = false;

  //타이머를 해제한다.
  scroll_Timer->Enabled  = false;
  scroll_Timer->Interval = 500;
  //}-----------------------------

  return;

}

void __fastcall Tgui_scroll_h_Form::FormMouseMove(TObject *Sender,
      TShiftState Shift, int X, int Y)
{
  //[2006.10.30.월][생성!!!]{---------------------------------------
  //"thumb" 를 마우스로 집어끄는 것을 처리한다.
  //이동 거리를 계산하여 _position 값을 계산후 다시 그려 주면 된다.
  //}---------------------------------------------------------------

  //[VAR]
  //{
      int   movesize;
      int   position;
  //}

  if(Shift.Contains(ssLeft))
  {
    //[예외처리]{------------------------------
    //thumb 를 집어 끄는 경우만 처리해야 한다.
    if(_thumb_selected != true) return;
    //}----------------------------------------

    //새로 이동한 _move_size 값은 이전 _move_size 값에 "집어끈" 이동거리를 더하면 된다.
    movesize = _mouse_down_move_size + (X - _mouse_down_point.x);

    //새로운 position 값을 계산한다.
    if(_scroll_size == 0)
    {
      //문모가 0 이 되면 안되므로 별도 처릴한다.
      position = 0;

    }
    else
    {
      position = (movesize * (_max - _min)) / _scroll_size + _min;

    }

    //_position 값을 수정하고 자동으로 다시 scrollbar 를 그려준다.
    _Position(position);

  }

  return;

}

void __fastcall Tgui_scroll_h_Form::scroll_TimerTimer(TObject *Sender)
{
  //[2006.11.01.수][생성!!!]{--------------------------------
  //화살표를 사용하여 자동 scroll 되는 시간 간격을 설정한다.
  //}--------------------------------------------------------

  //화살표가 눌려있는 동안은 계속 position 을 1 씩 증가시켜  scroll 해준다.
  if     (_arrow_left_downed == true)
  {
    _Position(--_position);

    //timer 로 자동 스크롤하는 경우는 20ms 정도의 주기를 사용한다.
    scroll_Timer->Interval = 20;

  }
  else if(_arrow_right_downed == true)
  {
    _Position(++_position);

    //timer 로 자동 스크롤하는 경우는 20ms 정도의 주기를 사용한다.
    scroll_Timer->Interval = 20;

  }

  return;

}
//---------------------------------------------------------------------------

