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

#include <vcl.h>
#pragma hdrstop

#include "ide_BalloonBox.h"


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tide_BalloonBox_Form *ide_BalloonBox_Form;
//---------------------------------------------------------------------------
                     

//[2008.02.03.일][생성!!!]{-------------------------------------------------------------
//<ide_msgbox> 를 사용하여 생성하였다.
//이는 [풍선도움말] 등과 같은 기능으로 각종 컨트롤의 자세한 설명을 표시하는데 사용된다.
//보여지기 지정후 일정 시간이 지나야 보여져야 하므로 한개의 타이머를 가진다.
//자신에게서 [초점] 이 사라지면 자동으로 보이지 않게 만들어야 한다.
//표시되는 문자열의 최대 폭에 맞게 전체 폭이 정해져야한다.
//보여질때는 가능하면 해당 컨트롤의 중간/아래에 보여지게 만든다.
//}-------------------------------------------------------------------------------------


#include  "main.h"
#include  "ide_main.h"
#include  "ide_library.h"
#include  "gui.h"


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

  //}

  //[초기화]
  //{
      //--------------------------------------------------------------------------
      //크기는 표시되는 내용에 따라 자동으로 처리 되지만 일단 임의 값을 기록한다.
      this->Left     = 0;
      this->Top      = 0;
      this->Width    = 100;
      this->Height   = 16;
      this->Color    = clWhite;

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

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

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

  //[글꼴 설정]
  //{
      //[기본 끌꼴 등록]{------------------------------------------------
      //모든 프로그램에서 기본적으로 사용하는 [system 글꼴] 을 등록한다.
      FONTPACK_SetDefault(&_font);
      //}----------------------------------------------------------------

      //[editor debug margin]
      //{
          _font.margin_size = 0;
      //}

      //문자 margin 을 설정한다.
      _font.offset_left   = 0;
      _font.offset_right  = 0;
      _font.offset_top    = 0;
      _font.offset_bottom = 1;

      //[2010.01.26.화][추가!!!]{---
      _font.en_offset_left  = 0;
      _font.en_offset_right = 0;
      //}---------------------------

  //}

  //[속성초기화]
  //{
      //기본적으로 선택되지 않은 상태.
      _pointerSelected = false;

  //}

  //[지시자 설정]
  //{
      //왼쪽 위치지정.
      _pointerLeft   = d_ide_BalloonBox_pointerLeft;

      //높이 지정.
      _pointerHeight = d_ide_BalloonBox_pointerHeight;

      //실제 사용할 caption 폭을 설정한다.
      //_font.margin_size 는 처음 기본값인 0 을 사용한다.(한번만 그려주면 된다.)
      _pointerWidth  = d_ide_BalloonBox_pointerWidth;
  //}

  //[바탕색]
  //{
      //테두리색의 밝은 색을 테마색으로 바탕에 칠한다.

      //칠할 색을 수정한다.
      BMP_Get_Bright_Color(_ide_option->color_0, IDE_BRIGHT_BalloonBox, &_back_color);

  //}

  this->Visible = true;
  this->Visible = false;

  //[설정 적용]
  //{
      //[2008.02.05.화][추가!!!]{---------------------------------
      //환경 설정 내용을 반영하는 것으로 수정한다.
      this->AlphaBlend      = _ide_option->balloonHelpAlphaBlend;

      //이 값은 225 로 고정한다.
      this->AlphaBlendValue = 225;
      //}---------------------------------------------------------
  //}

}

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

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

}

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

void __fastcall Tide_BalloonBox_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;

  }
  else if(Message.Msg == WM_KILLFOCUS)
  {
    //현재 타미어가 돌고 있다면 초기화 하고 정지시킨다.
    balloon_Timer->Interval = 1000;
    balloon_Timer->Enabled  = false;

    //촛점을 읽은 경우는 보이지 않게 만든다.
    this->Hide();

  }

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

  //}

}

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

void __fastcall Tide_BalloonBox_Form::_FormCut(void)
{
  //[2006.11.07.화][생성!!!]{----------------------------------------------------
  //폼의 caption 의 모양을 보기 좋게 하기 위하여 caption 의 영역을 제외한 나머지
  //영역의 폼을 제거해 준다.(구멍을 뚫어준다.)
  //여러개의 [사각형] 모양으로 구멍을 뚫어준다.
  //}----------------------------------------------------------------------------

  //[VAR]
  //{
      HRGN    //대상 폼.
              rgn_main,

              //위의 [지시자] 영역을 일단 완전히 삭제한다.
              rgn_cut_rect,

              //[지시자] 가 그려질 삼각형 영역을 얻는다.
              rgn_Pointer;

  //}


  //[Form 초기화]
  //{
      //포인터 초기화.
      rgn_main = 0;

      //Form 의 영역 정보를 얻는다.
      GetWindowRgn(this->Handle, rgn_main);

      //일단 현재 Form 영역을 지운다.
      DeleteObject(rgn_main);
  //}

  //[영역 생성]
  //{
      //새로운 영역을 생성한다.
      rgn_main = CreateRectRgn(0, 0, this->Width, this->Height);

      //[구멍 뚫을 영역 지정]
      //{
          //지시자 영역.
          rgn_cut_rect = CreateRectRgn(0, 0, this->Width, 12);

      //}

      //[지시자 영역 만들기]
      //{
          POINT pointerPoint3[3];

          //왼쪽 아래점.
          pointerPoint3[0].x = _pointerLeft;
          pointerPoint3[0].y = 12;

          //가운데 윗점.
          pointerPoint3[1].x = _pointerLeft;
          pointerPoint3[1].y = 0;

          //오른쪽 아래점.
          pointerPoint3[2].x = _pointerLeft + _pointerWidth;
          pointerPoint3[2].y = 12;

          //직각삼각형 영역 생성.
          rgn_Pointer = CreatePolygonRgn(pointerPoint3, 3, ALTERNATE);

      //}

      //지시자가 위치하는 전체 사각형 영역은 오려낸다.
      CombineRgn(rgn_main, rgn_main, rgn_cut_rect, RGN_DIFF);

      //[지시자] 영역은 함성하여 남겨 주어야 한다.
      CombineRgn(rgn_main, rgn_main, rgn_Pointer, RGN_OR);

      SetWindowRgn(this->Handle, rgn_main, TRUE);
  //}

  //[구멍 뚫기]
  //{
      //--------------------------
      //오려낼 영역만 오려낸다.
      DeleteObject(rgn_cut_rect);
      //--------------------------
  //}

}

void __fastcall Tide_BalloonBox_Form::_Border(void)
{
  //[2006.11.07.화]{----------------------------------------------------------
  //Form 전체의 테두리를 만든다.
  //두께는 4pixel, 동서남 3 면만 그리면 된다.
  //테두리는 직접 보이는 것이고 내용에 영향을 주지 않아야 하므로 직접 그린다.

  //[2007.03.18.일][수정!!!]
  //1 pixel 의 [통합개발환경] 전체 테두리를 마지막에 그려준다.
  //이는 윤곽을 더 뚜렷하게 하기 위한 것이다.
  //}-------------------------------------------------------------------------

  //[VAR]
  //{
      TRect  trect;
      int    color = clBlack;//_ide_option->color_0;

  //}

  //[윤곽선 만들기]
  //{
      //[왼쪽]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(0, 2);
      _bmp_->Canvas->LineTo(0, this->Height);

      //[오른쪽]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(this->Width - 1, 0);
      _bmp_->Canvas->LineTo(this->Width - 1, this->Height);

      //[아래쪽]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(0, this->Height - 1);
      _bmp_->Canvas->LineTo(this->Width - 1, this->Height - 1);

      //[왼쪽 위]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(0, 12);
      _bmp_->Canvas->LineTo(_pointerLeft + 1, 12);

      //[오른쪽 위]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(_pointerLeft + _pointerWidth, 12);
      _bmp_->Canvas->LineTo(this->Width - 1, 12);

      //[지정자 왼쪽 세로]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(_pointerLeft, 0);
      _bmp_->Canvas->LineTo(_pointerLeft, 12);

      //[지정자 오른쪽 세로]
      _bmp_->Canvas->Pen->Color = color;
      _bmp_->Canvas->MoveTo(_pointerLeft - 1, 0);
      _bmp_->Canvas->LineTo(_pointerLeft + _pointerWidth, 12);

  //}

}

void __fastcall Tide_BalloonBox_Form::_Cal_pointerLeft(int   pX,
                                                       char  *pBalloonStr)
{
  //[2012.03.30.금][생성!!!]{-----------------------------------------------------
  //[꼭지점] 좌표와 [출력문자열] 을 전달 받아 [화면영역] 정보를 바탕으로
  //<_pointerLeft> 값을 계산한다.
  //단, <_pointerLeft> 는 최소 16 의 크기를 갖아야 한다.
  //
  //이는 위치에 따라 [풍선도움말] 오른편이 화면에서 사라지는 것을 막고
  //모든 내용이 다 보여지게 하기 위한것.
  //
  //X 좌표만 관계한다.
  //
  //[주의!!!]---------------------------------------------------------------------
  //이 함수는 <_BalloonBox()>, <_BalloonBoxInPart()>, <_BalloonBoxPos()> 함수에서
  //항상 가장 먼저 사용되어야 한다.
  //정확한 <_pointerLeft> 값이 먼저 산출되어야 한다.
  //}-----------------------------------------------------------------------------

  //[VAR]
  //{
      //임시 계산된 <Left> 위치.
      int  left;

      //오른쪽 사라진 폭.
      int  hideWidth;

      //문자열 출력영역 크기 정보.
      int  text_width;
      int  text_height;

      int  width;

      //[꼭지점] 오른쪽 폭.
      int  prw;

  //}

  //[출력문자열 영역크기/적용할 폭 구하기]
  //{
      //[2012.03.30.금][참고!!!]{---------------------------------------
      //이 부분은 <Shape()> 함수안에서도 처리되는 것으로 중복되지만
      //정확한 출력 영역정보를 미리 알기 위하여 이곳에서도 처리해 준다.
      //처리 내용은 완전히 동일.
      //}---------------------------------------------------------------

      //출력할 문자열의 출력시 영역 크기 정보를 구한다.(실제 출력하지는 않는다.)
      FONT_Get_StringOutAreaInfo(&_font, d_FONTSTYLE_default, _balloonStr, &text_width, &text_height);

      //출력 문자열 영역 크기 얻기.
      //<4*2> 는 실제 <_font.margin_size> 값으로 보기 좋게 양쪽에 적용하는것.
      //---------------------v
      width = text_width + (4*2)*2;

      //[최소 크기 유지]
      //{
          //[!]{---------------------------------------------------------
          //[제목막대] 와 [엄지그림] 와 [버튼] 의 공간을 위하여 최소한의
          //크기 이상으로 작아지지 않도록 최소 크기를 유지한다.
          //}------------------------------------------------------------

          if(width < _pointerWidth * 2)
          {
            width  = _pointerWidth * 2;

          }

      //}

  //}

  //[가상 위치 얻기]
  //{
      //[!]{--------------------------------------------------------------
      //현재 상태로 출력되는 <Left> 위치값을 미리 계산한다.
      //이는 출력되는 <Left> 값에 따라 <_pointerLeft> 값이 달라지기 때문.
      //}-----------------------------------------------------------------

      //임시 위치를 확정.
      left = pX - d_ide_BalloonBox_pointerLeft;

  //}

  //[꼭지점 오른쪽 영역 확인]
  //{
      //[2012.03.30.금][추가!!!]{------------------------------------
      //[꼭지점] 오른쪽 영역이 화면상에서 가려져 보이지 않는 경우는
      //이 크기를 계산하여 <_pointerLeft> 위치를 [오른쪽] 으로 이동.
      //단, [꼭지점] 오른쪽으로 최소 [16] 크기는 유지해야 한다.
      //}------------------------------------------------------------

      //[2012.03.30.금][수정!!!]{-----------------------------------
      //오른쪽 세로선이 화면 선과 겹치지 않도록 약간의 여유를 준다.
      //}-----------------------------------------------------------
      //------------------------------------v
      if((left + width) >= (Screen->Width - 4))
      {
        hideWidth = (left + width) - (Screen->Width - 4);

        _pointerLeft = d_ide_BalloonBox_pointerLeft + hideWidth;

      }
      else
      {
        //[화면영역] 안에 있다면 기본 값으로 설정.
        _pointerLeft = d_ide_BalloonBox_pointerLeft;

      }

  //}

  //[최소 지정]
  //{
      //[!]{------------------------------------------
      //[꼭지점] 오른쪽 영역은 최소 <16> 크기를 유지.
      //}---------------------------------------------

      //[꼭지점] 오른쪽 영역 폭 계산.
      prw = width - (_pointerLeft + _pointerWidth);

      if(prw <= d_ide_BalloonBox_pointerLeft)
      {
        //[꼭지점] 오른쪽 영역을 최소 <16> 크기를 유지하도록 <_pointerLeft> 값 설정.
        _pointerLeft = width - d_ide_BalloonBox_pointerLeft - _pointerWidth;

      }

  //}

}

void __fastcall Tide_BalloonBox_Form::_BalloonBox(int   pX,
                                                  int   pY,
                                                  //일정 시간 뒤에 보여줄지 말지를 결정한다.
                                                  bool   pTimerUse,
                                                  //전달 글.
                                                  char  *pBalloonStr)
{
  //[2008.02.03.일][수정!!!]{----------------------------------------------------------------
  //즉시 보여주어야 하는 경우와 일정 시간을 지연 후 보여주어야 하는 경우를
  //구분하여 처리해야 한다.
  //이는 해당 컨트롤에 위치할때마다 계속 내용이 그려지는 것을 막기 위한 것이다.
  //
  //pTimerUse : true
  //            일단 문자열을 임시 버퍼에 저장해 놓고 있다가 해당 시간이 만료되면 보여준다.
  //            이경우 시간이내에 [초점] 을 잃게 되는 경우는 아무 것도 처리하지 않으면 된다.
  //
  //pTimerUse : false
  //            이 경우는 즉시 내용을 보여 주어야 하는 경우이다.
  //
  //[2012.03.30.금][추가!!!]-----------------------------------------------------------------
  //[풍선도움말] 전체가 항상 화면에 모두 보이도록 [꼭지점] 위치를 자동 결정.
  //화면 오른쪽으로 가려지는 부분이 발생하지 않도록 하기위한것.
  //
  //[2012.05.07.월][수정!!!]-----------------------------------------------------------------
  //[맷돌C:GUI] 동작후 [가장 앞으로 보이기] 안되는 문제 수정.
  //}----------------------------------------------------------------------------------------

  //[기본 설정 저장]
  //{
      //즉시 보여주건, 시간 지연을 하건 상관없이 무조건 저장해 주어야 하는 정보들.

      //표시 문자열.
      STR_Assign(_balloonStr, pBalloonStr);

      //[꼭지점 위치 조정]
      //{
          //[2012.03.30.금][추가!!!]{-------------------------------------------
          //위치를 미리 설정해 보고 정확한 <_pointerLeft> 값을 얻는다.
          //이는 [풍선도움말] 의 오른쪽이 가려지는 부분 없이 전체가 [화면] 안에
          //다 보이도록 [꼭지점] 위치를 조정해 주기 위한것.
          //
          //[주의!!!]-----------------------------------------------------------
          //반드시 <this->Left> 위치가 결정되기 전에 사용돼야 한다.
          //}-------------------------------------------------------------------

          _Cal_pointerLeft(pX, pBalloonStr);

      //}

      //표시 위치.(이는 지정자 꼭지점 위치가 된다.)
      this->Left = pX - _pointerLeft;
      this->Top  = pY;

  //}



  if(pTimerUse != true)
  {
    //이 경우는 즉시 보여 주어야 한다.

    //[타이머 끄기]
    //{
        balloon_Timer->Interval = 1000;
        balloon_Timer->Enabled  = false;
    //}

    //[2012.03.30.금][수정!!!]
    _Shape(true);

    //[보이기]
    //{
        //[2012.05.07.월][추가!!!]{------------------------------------------
        //아래 <this->BringToFront()> 추가와 같은 이유인데
        //원래 지정한 것이나 재지정한다.
        //단, 어떤 이유인지는 알수 없으나 [맷돌C:GUI] 를 돌린후 우선순위
        //문제로 [가장 앞으로 보이기] 가 제대로 복구되지 않는 경우가 있다.
        //이를 완전히 초기화 하기 위하여 [기본폼] 으로 다시 지정후
        //[가장위] 로 다시 지정하면 다시 완벽하게 복구된다.
        //실험결과 여러 상황에서도 문제 없이 잘 [가장 위로 보이기] 동작된다.
        //
        //[주의!!!]----------------------------------------------------------
        //반드시 아래 순서대로 처리해야 한다.
        //
        //1) this->FormStyle = fsNormal;
        //2) this->FormStyle = fsStayOnTop;
        //3) this->BringToFront();
        //4) this->Show();
        //}------------------------------------------------------------------

        if(this->Visible != true)
        {
          this->FormStyle = fsNormal;
          this->FormStyle = fsStayOnTop;

          this->BringToFront();

          this->Show();

          this->SetFocus();

        }

    //}

    //더이상 처리하지 않고 종료한다.
    return;

  }

  if(_ide_option->balloonHelpUse == true)
  {
    //[2008.02.05.화][수정!!!]{----------------------------
    //[풍선도움말] 기능을 사용하는 경우만 보여주어야 한다.
    //}----------------------------------------------------

    //[타이머 구동]
    //{
        balloon_Timer->Interval = 1000;
        balloon_Timer->Enabled  = true;
    //}

  }

}

void __fastcall Tide_BalloonBox_Form::_BalloonBoxPos(int pX, int pY)
{
  //[2008.02.03.일][생성!!!]{------------------------------------------------------------
  //단지 위치만 계속 입력 받아 수정해준다.
  //이는 컨트롤에 진입시에 [문자열] 등이 설정되지만 위치가 좋지 않을수 있으므로
  //일단 계속 위치는 입력 받아서 보여질때 정확한 위치에 있을수 있게한다.
  //이는 문자열까지 계속 입력되지 않게 만들기 위한 것이다.
  //단, 이미 이 [풍선도움말] 이 보이는 상태라면 계속 [입력지정자] 를 따라 다니지
  //않도록 입력 받은 내용을 무시한다.
  //이 위치는 지정자 꼭지점 위치가 된다.
  //
  //[2012.03.30.금][추가!!!]-------------------------------------------------------------
  //[풍선도움말] 전체가 항상 화면에 모두 보이도록 [꼭지점] 위치를 자동 결정.
  //화면 오른쪽으로 가려지는 부분이 발생하지 않도록 하기위한것.
  //
  //[주의!!!]----------------------------------------------------------------------------
  //단지 위치만 내부적으로 표시하나 반드시 <_Cal_pointerLeft()> 함수를 적용해야 한다.
  //그렇지 않은 경우 일반적인 [풍선도움말] 보이기시에 <_pointerLeft> 값이 제대로
  //지정되지 않아 <_BalloonBox()>, <_BalloonBoxInPart()> 함수로 [풍선도우말] 을
  //보일때 제위치에 나오지 않고 약간 오차가 발생하게 된다.
  //금일, 이전에 [맷돌C] 로 만든 [맷돌28호-설정기] 에서 [풍선도움말] 을 점검하다
  //발견하고 적용한다.
  //
  //<_BalloonBoxPos()> 를 사용하지 않고 바로 <_BalloonBox()>, <_BalloonBoxInPart()> 를
  //사용하는 경우는 문제가 되지 않지만, 일반적인 [풍선도움말] 처리시에는 항상 내부적으로
  //<_BalloonBoxPos()> 으로 미리 위치를 계산해 놓기 때문에 반드시 필요한 것이다
  //}-------------------------------------------------------------------------------------

  //이미 보이고 있는 상태라면 무시한다.
  if(this->Visible == true) return;

  //[꼭지점 위치 조정]
  //{
      //[2012.03.30.금][추가!!!]{-------------------------------------------
      //위치를 미리 설정해 보고 정확한 <_pointerLeft> 값을 얻는다.
      //이는 [풍선도움말] 의 오른쪽이 가려지는 부분 없이 전체가 [화면] 안에
      //다 보이도록 [꼭지점] 위치를 조정해 주기 위한것.
      //
      //[2012.03.30.금][주의!!!]--------------------------------------------
      //반드시 <this->Left> 위치가 결정되기 전에 사용돼야 한다.
      //}-------------------------------------------------------------------

      //이미 설정된 문자열을 사용하여 계산.
      _Cal_pointerLeft(pX, _balloonStr);

  //}

  this->Left = pX - _pointerLeft;
  this->Top  = pY;

}

void __fastcall Tide_BalloonBox_Form::_Hide(void)
{
  //[2008.02.03.일][생성!!!]{---
  //보이지 않게 만든다.
  //}---------------------------

  //현재 타미어가 돌고 있다면 초기화 하고 정지시킨다.
  balloon_Timer->Interval = 1000;
  balloon_Timer->Enabled  = false;

  //촛점을 읽은 경우는 보이지 않게 만든다.
  this->Hide();

}

void __fastcall Tide_BalloonBox_Form::_Shape(//[2012.03.30.금][추가!!!]
                                             //내부 <_FormCut()> 을 처리할지(true) 말지(false)를 결정.
                                             bool  pFormCut)
{
  //[2008.02.03.일][생성!!!!!!]{--------------------------------------------------------
  //표시할 문자열에 맞게 내용을 만들어 준다.
  //
  //[2012.03.30.금][수정!!!]------------------------------------------------------------
  //<_Shape()> 함수는 현재 거의 모든 부분에서 사용되고 있는데 이 안의
  //<_FormCut()> 함수는 꼭 필요한 경우만 사용되어야 한다.
  //너무 빈번하게 사용하는 경우 [자원부족:오류] 가 발생.
  //따라서, [크기 조정] 과 [꼭지점:위치 변경], [문자열 설정] 등의 경우만 적용해야 한다.
  //이를 위하여 <bool pFormCut> 추가.
  //}-----------------------------------------------------------------------------------

  //[VAR]
  //{
      TRect  rect;
      TRect  rect_caption;

      int    w, h;

      //문자열 출력영역 크기 정보.
      int    text_width;
      int    text_height;

      int    width, height;

  //}

  //[출력문자열 영역크기 구하기]
  //{
      //출력할 문자열의 출력시 영역 크기 정보를 구한다.(실제 출력하지는 않는다.)
      FONT_Get_StringOutAreaInfo(&_font, d_FONTSTYLE_default, _balloonStr, &text_width, &text_height);

  //}

  //[크기 조정]
  //{
      //출력 문자열 영역 크기에 맞게 bmp 크기를 조정한다.
      //<4*2> 는 실제 <_font.margin_size> 값으로 보기 좋게 양쪽에 적용하는것.
      //----------------------v
      width  = text_width + (4*2)*2;

      height = text_height +
               //캡션바 높이.
               _pointerHeight + 12;

      //[최소 크기 유지]
      //{
          //-------------------------------------------------------------
          //[제목막대] 와 [엄지그림] 와 [버튼] 의 공간을 위하여 최소한의
          //크기 이상으로 작아지지 않도록 최소 크기를 유지한다.
          if(width < _pointerWidth * 2)
          {
            width  = _pointerWidth * 2;

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

  //[bmp 크기 조정]
  //{
      //출력 문자열 영역 크기에 맞게 bmp 크기를 조정한다.
      _bmp_->Width  = width;
      _bmp_->Height = height;
  //}

  //[form 크기 조정]
  //{
      this->Width  = _bmp_->Width;
      this->Height = _bmp_->Height;
  //}

  //[폼 오려내기]
  //{
      //[2012.03.30.금][수정!!!]{---------------------------------
      //[크기조정/꼭지점 위치 변경/문자열 설정] 등의 경우만 처리.
      //}---------------------------------------------------------

      if(pFormCut == true) { _FormCut(); }

  //}

  //[모양 그리기]
  //{
      //[전체 배경 처리]
      //{
          //[영역정보]{-------------------
          rect = _bmp_->Canvas->ClipRect;
          //}-----------------------------

          //[바탕 지우기]{---------------------------
          _bmp_->Canvas->Brush->Color = _back_color;
          _bmp_->Canvas->FillRect(rect);
          //}----------------------------------------

      //}

  //}

  //[알림글 내용]
  //{
      _font.margin_size = 4*2;

      FONT_Out_String2(_bmp_, &_font, 0, _pointerHeight + 4,
                       IDE_COLOR_1, IDE_COLOR_2, true,
                       _balloonStr,
                       d_FONT_underline_no, true, 0, IDE_COLOR_1,
                       &w, &h);
      
  //}

  //[테두리]
  //{
      _Border();

  //}

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

}

void __fastcall Tide_BalloonBox_Form::_Draw(void)
{
  //[2006.11.07.화][생성!!!]

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

}

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

void __fastcall Tide_BalloonBox_Form::balloon_TimerTimer(TObject *Sender)
{
  //[2008.02.03.일][생성!!!]{---------------------------------
  //이 경우 일정 시간이 지났으므로 이 폼을 보여준다.
  //
  //[2012.05.05.토][수정!!!]----------------------------------
  //[맷돌C:GUI] 동작후 [가장 앞으로 보이기] 안되는 문제 수정.
  //}---------------------------------------------------------

  //[2008.02.05.화][추가!!!]{---------------------
  //[풍선도움말] 이 사용설정인 경우만 처리한다.
  if(_ide_option->balloonHelpUse != true) return;
  //}---------------------------------------------

  //[초기화]
  //{
      balloon_Timer->Interval = 1000;
      balloon_Timer->Enabled  = false;

  //}

  //[내용 만들기]
  //{
      //[2012.03.30.금][수정!!!]{---------------------------------------
      //타이머로 보이는 경우는 [풍선도움말] 을 재설정하고 보이는 경우로
      //반드시 [폼잘라내기] 를 실행하도록 설정.
      //}---------------------------------------------------------------
      //-----v
      _Shape(true);

  //}

  //[보이기]
  //{
      //[2012.05.07.월][추가!!!]{------------------------------------------
      //아래 <this->BringToFront()> 추가와 같은 이유인데
      //원래 지정한 것이나 재지정한다.
      //단, 어떤 이유인지는 알수 없으나 [맷돌C:GUI] 를 돌린후 우선순위
      //문제로 [가장 앞으로 보이기] 가 제대로 복구되지 않는 경우가 있다.
      //이를 완전히 초기화 하기 위하여 [기본폼] 으로 다시 지정후
      //[가장위] 로 다시 지정하면 다시 완벽하게 복구된다.
      //실험결과 여러 상황에서도 문제 없이 잘 [가장 위로 보이기] 동작된다.
      //
      //[주의!!!]----------------------------------------------------------
      //반드시 아래 순서대로 처리해야 한다.
      //
      //1) this->FormStyle = fsNormal;
      //2) this->FormStyle = fsStayOnTop;
      //3) this->BringToFront();
      //4) this->Show();
      //}------------------------------------------------------------------

      if(this->Visible != true)
      {
        this->FormStyle = fsNormal;
        this->FormStyle = fsStayOnTop;

        this->BringToFront();

        this->Show();

        this->SetFocus();

      }

  //}

}

