
//[2012.06.05.화][중요수정!!!]{-------------------------------------------------
//<_bmp_> 를 이전의 [화면크기] 로 고정하던 것을 [그림부품] 크기에 맞게
//자동 조정되는 것으로 수정하였으며, 관련 사용 부분 역시 수정되었다.
//이는 메모리를 절약하고 쓸데없이 그려지는 시간을 줄여 보다 고속화 하기 위한것.
//}-----------------------------------------------------------------------------


#include <vcl.h>
#pragma hdrstop

#include "msg_msg.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tmsg_msg_Form *msg_msg_Form;
//---------------------------------------------------------------------------


#include "main.h"
#include "ide_main.h"
#include "ide_msg.h"
#include "ide_menu.H"
#include "ide_mbutton.h"

#include "ide_library.h"
#include "gui.h"


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

  //}

  //[form]
  //{
      this->Left     = 0;
      this->Top      = ((Tide_msg_Form *)Owner)->_captionbar_Form->Top +
                       ((Tide_msg_Form *)Owner)->_captionbar_Form->Height - 1;
      this->Width    = ((TForm *)Owner)->Width;
      this->Height   = ((TForm *)Owner)->Height - this->Top;

      this->Color    = clWhite;
  //}

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

      //그림 영역 크기 설정.
      //[2012.06.05.화][수정!!!]
      //본체 크기로 설정(배경그림으로 지우는 방식이 아니라 꼭 필요한 만큼만 설정).
      _bmp_->Width  = this->Width;
      _bmp_->Height = this->Height;

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

  //[배경화면]
  //{
      //------------------------------------------------------------------------------
      //실제 그림 영역을 생성한다.
      _bmp_back_ = new Graphics::TBitmap;

      //[그림 경로]
      //{
          if(IDE_BACKBMP_entire)
          {
            //한개의 그림을 전체영역으로 사용하는 경우.
            _bmp_path = (AnsiString)_ide_option->ideBackpicturePath;

            //[확인]
            //[
                //[2007.12.04.화][추가!!!]
                //그림이 있는지 먼저 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //그림이 존재하지 않는 경우는 기본 그림으로 대체한다.
                  _bmp_path = IDE_BACKBMP_entire_path;

                }

                //기본 그림이 있는지 한번더 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //기본 그림 역시 존재하지 않는다면 그냥 표시하지 않는다.
                  _bmp_path = "";

                }

            //}

          }
          else
          {
            //지정된 전용 그림을 사용한다.
            _bmp_path = (AnsiString)_ide_option->msgBackPicturePath;

            //[확인]
            //[
                //[2007.12.04.화][추가!!!]
                //그림이 있는지 먼저 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //그림이 존재하지 않는 경우는 기본 그림으로 대체한다.
                  _bmp_path = IDE_BACKBMP_msg_path;

                }

                //기본 그림이 있는지 한번더 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //기본 그림 역시 존재하지 않는다면 그냥 표시하지 않는다.
                  _bmp_path = "";

                }

            //}

          }

      //}

      //[그림 확인]
      //{
          //[2007.12.04.화][추가!!!]
          //만일 그림이 없는 경우는 처리하지 않는다.
          if(_bmp_path == "")
          {
            //이 경우는 배경을 전부 흰색으로 칠해 주어야 한다.

            //크기지정.
            _bmp_back_->Width  = Screen->Width;
            _bmp_back_->Height = Screen->Height;

            //색칠하기.
            _bmp_back_->Canvas->Brush->Color = clWhite;
            _bmp_back_->Canvas->FillRect(_bmp_back_->Canvas->ClipRect);

          }
          else
          {
            //그림 읽어 들이기.
            BMP_LoadJpeg(_bmp_back_, _bmp_path, Screen->Width, Screen->Height, d_BMP_load_tile);

          }

      //}

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

      //배경 그림을 밝게 하여 문자가 잘 보기게 만든다.
      BMP_Brightness(_bmp_back_, _ide_option->msg_back_brightness);
      //------------------------------------------------------------------------------

  //}

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

      _font.margin_size   = 2;

      _font.offset_left   = 0;
      _font.offset_right  = 0;
      _font.offset_top    = 0;
      _font.offset_bottom = 0;

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

      //[행높이 구하기]{------------------------------------------------------------------------------------------
      //[글꼴] 의 크기를 알기 위한 CRLF 문자 출력.
      FONT_Out_Moonja(_bmp_, &_font, 0, 0, IDE_COLOR_1, IDE_COLOR_2, false, 0x0d0a, &_word_width, &_line_height);
      //----------------------------------------------------------------------------------------------------------
  //}

  //[환경변수]
  //{
      _buf_msg[0]    = '\0';
      _buf_msgSize   = 0;
      _buf_debug[0]  = '\0';
      _buf_debugSize = 0;

      //저장소 초기화.
      _buf[d_msg_msg]   = _buf_msg;
      _buf[d_msg_debug] = _buf_debug;

      //기본은 [출력내용] 이 보이게 된다.
      _text_index = d_msg_msg;

      _scroll_position[d_msg_msg]   = 0;
      _scroll_position[d_msg_debug] = 0;
  //}

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

  return;   

}

__fastcall Tmsg_msg_Form::~Tmsg_msg_Form(void)
{
  //[2012.04.29.일][수정!!!]{---------------
  //안전을 위하여 선언한 역순으로 삭제한다.
  //}---------------------------------------

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

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

}

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

void __fastcall Tmsg_msg_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 Tmsg_msg_Form::_Shape(void)
{
  //[2006.11.01.수][생성!!!]{-----------------------------------------

  //[2007.03.25.일][수정!!!]
  //[전체배경사용] 의 경우 한개의 배경을 사용하는 것처럽 보이게 한다.
  //}-----------------------------------------------------------------

  //[VAR]
  //{
      int   w, h;
  //}

  //[바탕색]
  //{
      //[2007.03.24.토][수정!!!]
      //배경종류에 따라 다르게 처리한다.

      if(IDE_BACKBMP_entire)
      {
        //이 경우는 한개의 그림을 여러창에서 나누어 사용해야 한다.

        if(ide_msg_Form == NULL) return;
        //[표시 시작 위치 계산]
        //{
            //크기가 변경되는 경우는 전체 바탕그림을 표시하는 시작 위치도 변경된다.
            //이는 마치 한개의 동일한 그림 위에 투명하게 위치하는 것같은 느낌을 주기 위한 것이다.
            _bmporg_x = 0;
            _bmporg_y = this->Parent->Top +
                        //이 ide_msg_Form 의 [제목줄] 높이.
                        16 +
                        //서로 1 pixel 씩 겹치는 것을 반영한다.(한개만 있으면 됨.)
                        1 -
                        //실제 그림이 표시 되지 않는 맨 위의 영역은 제외 시켜야 한다.
                        (
                         //전체 [제목줄] 과 주항목 자체 높이만큼 제외한다.
                         ide_menu_Form->Top + ide_menu_Form->Height +
                         //주버튼높이는 제외.
                         ide_mbutton_Form->Height +
                         //ide_tree_Form 의 [제목줄] 높이 제외.
                         //실제 그림은 이 [제목줄] 아래부터(순수하게 tree_tree_Form 부터) 표시되므로.
                         16
                        );
        //}

        //배경 그림으로 바탕을 지운다.
        BitBlt(_bmp_->Canvas->Handle, 0, 0,
               _bmp_->Width, _bmp_->Height,
               _bmp_back_->Canvas->Handle, _bmporg_x, _bmporg_y, SRCCOPY);

      }
      else
      {
        //배경 그림으로 바탕을 지운다.
        BitBlt(_bmp_->Canvas->Handle, 0, 0,
               _bmp_->Width, _bmp_->Height,
               _bmp_back_->Canvas->Handle, 0, 0, SRCCOPY);

     }
  //}

  //[테두리 만들기]
  //{
      _bmp_->Canvas->Pen->Color   = _ide_option->color_0;
      _bmp_->Canvas->Pen->Width   = 1;
      _bmp_->Canvas->Brush->Style = bsClear;
      _bmp_->Canvas->Rectangle(_bmp_->Canvas->ClipRect);
  //}

  //[test 문자열]
  //{
      FONT_Out_StyleString2(_bmp_, &_font, 0, 2,
                            IDE_COLOR_1, IDE_COLOR_2, true,
                            d_FONTSTYLE_default,
                            _buf[_text_index],
                            d_FONT_underline_no, true, 0, _ide_option->color_0,
                            &w, &h);
  //}

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

  return ;

}

void __fastcall Tmsg_msg_Form::_Resize(void)
{
  //[2006.11.01.수][생성!!!]{------------------------------
  //크기를 조정한다.

  //[2007.03.25.일][수정!!!]
  //[전체배경사용] 인 경우는 무조건 다시 그려 주어야 한다.
  //}------------------------------------------------------

  _Height(this->Parent->Height - this->Top, false);

  //마지막 한번만 [다시 그리기] 한다.
  //--------------------------v
  _Width(this->Parent->Width, true);
  

  //[2012.06.05.화][주석처리!!!]{---
  //위의 새로운 함수로 대체.
  //}-------------------------------
  /*
  this->Width    = this->Parent->Width;
  this->Height   = this->Parent->Height - this->Top;

  //[전체배경사용][2007.03.25.일][추가!!!]
  //{
      if(IDE_BACKBMP_entire)
      {
        //이 경우는 다시 전체 배경 그림의 정확한 위치를 표시할수 있도록 다시 출력한다.
        //그림 위에 문자열이 있으므로 문자열을 다시 출력하면 자동으로 그림은 배경을 지우는
        //과정에서 정확한 위치가 표시된다.
        _Text(_text_index);

      }
  //}
  */

}

void __fastcall Tmsg_msg_Form::_Width(int   pWidth,
                                      //[다시 그리기] 하는 경우는 <true>.
                                      bool  pRePaint)
{
  //[2012.06.05.화][수정!!!]

  this->Width  = pWidth;

  _bmp_->Width = pWidth;

  //[다시 그리기]
  //{
      //[!]{--------------------------------------
      //<_bmp_> 크기가 변경되었으므로 다시 그리되
      //다시 그리기 요청이 있는 경우만 처리.
      //}-----------------------------------------

      if(pRePaint == true)
      {
        _Text(_text_index);

      }

  //}

}

void __fastcall Tmsg_msg_Form::_Height(int   pHeight,
                                       //[다시 그리기] 하는 경우는 <true>.
                                       bool  pRePaint)
{
  //[2012.06.05.화][수정!!!]

  this->Height  = pHeight;

  _bmp_->Height = pHeight;

  //[다시 그리기]
  //{
      //[!]{--------------------------------------
      //<_bmp_> 크기가 변경되었으므로 다시 그리되
      //다시 그리기 요청이 있는 경우만 처리.
      //}-----------------------------------------

      if(pRePaint == true)
      {
        _Text(_text_index);

      }

  //}

}

void __fastcall Tmsg_msg_Form::_Draw(void)
{
  //[2006.11.01.수][생성!!!]

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

  return;

}

void __fastcall Tmsg_msg_Form::_Text(int  pTEXTindex)
{
  //[2006.11.02.목][생성!!!]{---------------------------------------------
  //문자열 버퍼의 내용을 출력한다.
  //이는 문자열을 추가하는 기능은 없고, 단지 표시하는 기능만 있는 것이다.
  //
  //[2012.06.05.화][수정!!!]----------------------------------------------
  //}---------------------------------------------------------------------

  //[VAR]
  //{
      int  w, h;
      int  scroll_v_position;
      int  scroll_h_position;

  //}

  //[바탕색]
  //{
      //[2007.03.24.토][수정!!!]
      //배경종류에 따라 다르게 처리한다.

      if(IDE_BACKBMP_entire)
      {
        //이 경우는 한개의 그림을 여러창에서 나누어 사용해야 한다.

        //[2012.06.05.화][추가!!!]{-----------------------------------------
        //[출력창] 이 처음 생성시 [크기조정] 시에도 호출될수 있으므로
        //반드시 추가.
        //이는 금일 <_bmp_> 를 이전의 [화면크기] 고정에서 [그림부품] 크기로
        //수시 변경될수 있도록 수정한것과 관련이 있다.
        if(ide_msg_Form == NULL) return;
        //}-----------------------------------------------------------------

        //[표시 시작 위치 계산]
        //{
            //크기가 변경되는 경우는 전체 바탕그림을 표시하는 시작 위치도 변경된다.
            //이는 마치 한개의 동일한 그림 위에 투명하게 위치하는 것같은 느낌을 주기 위한 것이다.
            _bmporg_x = 0;
            _bmporg_y = this->Parent->Top +
                        //이 ide_msg_Form 의 [제목줄] 높이.
                        16 +
                        //서로 1 pixel 씩 겹치는 것을 반영한다.(한개만 있으면 됨.)
                        1 -
                        //실제 그림이 표시 되지 않는 맨 위의 영역은 제외 시켜야 한다.
                        (
                         //전체 [제목줄] 과 주항목 자체 높이만큼 제외한다.
                         ide_menu_Form->Top + ide_menu_Form->Height +
                         //주버튼높이는 제외.
                         ide_mbutton_Form->Height +
                         //ide_tree_Form 의 [제목줄] 높이 제외.
                         //실제 그림은 이 [제목줄] 아래부터(순수하게 tree_tree_Form 부터) 표시되므로.
                         16
                        );
        //}

        //배경 그림으로 바탕을 지운다.
        BitBlt(_bmp_->Canvas->Handle, 0, 0,
               _bmp_->Width, _bmp_->Height,
               _bmp_back_->Canvas->Handle, _bmporg_x, _bmporg_y, SRCCOPY);

      }
      else
      {
        //배경 그림으로 바탕을 지운다.
        BitBlt(_bmp_->Canvas->Handle, 0, 0,
               _bmp_->Width, _bmp_->Height,
               _bmp_back_->Canvas->Handle, 0, 0, SRCCOPY);

     }

  //}

  //[테두리 만들기]
  //{
      _bmp_->Canvas->Pen->Color   = _ide_option->color_0;
      _bmp_->Canvas->Pen->Width   = 1;
      _bmp_->Canvas->Brush->Style = bsClear;
      _bmp_->Canvas->Rectangle(_bmp_->Canvas->ClipRect);
  //}

  //[문자열]
  //{
      //[스크롤정보얻기]
      //{
          scroll_v_position = ide_msg_Form->_scroll_v_Form->_position;
          scroll_h_position = ide_msg_Form->_scroll_h_Form->_position;
      //}

      //수평 스크롤의 경우는 margin 값을 수정하여 출격 문자의 X 좌표에 offset 주는 방법을 사용한다.
      //수평 스크롤은 문자의 폭을 단위로 처리한다.
      _font.margin_size = (-1) * scroll_h_position * _word_width + 2;

      FONT_Out_StyleString2(_bmp_, &_font,
                            0,
                            //행단위로 이동한다.
                            (-1) * scroll_v_position * _line_height + 2,
                            IDE_COLOR_1, IDE_COLOR_2, true,
                            d_FONTSTYLE_default,
                            _buf[pTEXTindex],
                            d_FONT_underline_no, true, 0, clBlue,
                            &w, &h);

      _Draw();

  //}

  return;

}

/*
void __fastcall Tmsg_msg_Form::_BufAdd(int    pTextIndex,
                                       //저장소 처음부터 다시 저장하는 경우는 true.
                                       bool   pClearAdd,
                                       char  *pStr)
{
  //[2009.04.24.금][생성!!!]{------------------------------------------------
  //추가하는 문자열이 해당 저장소의 공간을 넘는 경우는 자동으로 현재 저장된
  //내용을 [삭제] 하고 [초기화] 한다.
  //[문자열] 을 추가하는 경우는 항상 이 함수를 통해서 처리한다.
  //
  //[2018.10.21.일][수정!!!]*************************************************
  //용량초과 검사를 한번만 하면 안된다.
  //
  //1) 용량 10K 인 경우.

  //2) 30K 문서를 연다면.
  //
  //3) 1) 를 다시 생성해도 3) 의 20K 가 남게 된다.
  //
  //4) 결국 10K 용량 저장소에 20K 를 넣게 되므로 출력하면 무조건 오류가된다.
  //
  //따라서, 용량을 다시 생성한 경우 문서의 남은 용량을 계산후 다시 검사.
  //죽, 충분히 10K 내부 용량에 저장할수 있는 문서량만 남을때 까지 계속
  //검사후 줄여야 한다.
  //
  //결국에는 최후의 10K 부분만 출력되야 정상.
  //}------------------------------------------------------------------------

  //[VAR]
  //{
      int  strLength = 0;

  //}

  //[문자열 길이 얻기]
  //{
      strLength = STR_Length(pStr);

  //}

  switch(pTextIndex)
  {
    case  d_msg_msg :
    {
      //[용량초과 확인]
      //{
          if((OPT_MsgBufSize <= (_buf_msgSize + strLength)) || (pClearAdd == true))
          {
            //현재 [저장소] 를 초기화 하고 새로 처음부터 다시 저장한다.
            _buf_msg[0]  = '\0';
            _buf_msgSize = 0;

          }

          //[문자열 추가]
          //{
              STR_Add(_buf_msg, pStr);

              //[저장소] 크기 수정.
              _buf_msgSize += strLength;

          //}

      //}

    } break;

    case  d_msg_debug :
    {
      //[용량초과 확인]
      //{
          if((OPT_DebugBufSize <= (_buf_debugSize + strLength)) || (pClearAdd == true))
          {
            //현재 [저장소] 를 초기화 하고 새로 처음부터 다시 저장한다.
            _buf_debug[0]  = '\0';
            _buf_debugSize = 0;

          }

          //[문자열 추가]
          //{
              STR_Add(_buf_debug, pStr);

              //[저장소] 크기 수정.
              _buf_debugSize += strLength;

          //}

      //}

    } break;

  }

}
*/

void __fastcall Tmsg_msg_Form::_BufAdd(int    pTextIndex,
                                       //저장소 처음부터 다시 저장하는 경우는 true.
                                       bool   pClearAdd,
                                       char  *pStr)
{
  //[2009.04.24.금][생성!!!]{------------------------------------------------
  //추가하는 문자열이 해당 저장소의 공간을 넘는 경우는 자동으로 현재 저장된
  //내용을 [삭제] 하고 [초기화] 한다.
  //[문자열] 을 추가하는 경우는 항상 이 함수를 통해서 처리한다.
  //
  //[2018.10.21.일][수정!!!]*************************************************
  //용량초과 검사를 한번만 하면 안된다.
  //
  //1) 용량 10K 인 경우.

  //2) 30K 문서를 연다면.
  //
  //3) 1) 를 다시 생성해도 3) 의 20K 가 남게 된다.
  //
  //4) 결국 10K 용량 저장소에 20K 를 넣게 되므로 출력하면 무조건 오류가된다.
  //
  //따라서, 용량을 다시 생성한 경우 문서의 남은 용량을 계산후 다시 검사.
  //죽, 충분히 10K 내부 용량에 저장할수 있는 문서량만 남을때 까지 계속
  //검사후 줄여야 한다.
  //
  //결국에는 최후의 10K 부분만 출력되야 정상.
  //}------------------------------------------------------------------------

  //[VAR]
  //{
      int  b; //[저장소] 크기.
      int  u; //[저장소] 사용된 크기(저장 시작 위치).
      int  e; //[저장소] 빈 크기.
      int  l; //<pStr> 길이.
      int  r; //<STR_SetLength()> 로 실제 처리된 문자열 길이.
      int  i;
      
  //}

  //[문자열 길이 얻기]
  //{
      l = STR_Length(pStr);

  //}

  switch(pTextIndex)
  {
    case  d_msg_msg :
    {
      //[전처리]
      //{
          if(pClearAdd == true)
          {
            _buf_msg[0]  = '\0';

            _buf_msgSize = 0;

          }

      //}

      b = OPT_MsgBufSize;

      //현재 저장돼 있는 크기가 저장 시작 위치.
      u = _buf_msgSize;

      i = 0;

      while(1)
      {
        //빈공간 크기 얻기.
        e = b - u;

        //문자열 끝까지만 처리-----------------v
        //'\0' 공간-----------------------v
        r = STR_SetLength(&(pStr[i]), e - 1, '\0', &(_buf_msg[u]));
        //<r> 은 처리된 문자열 길이([한글] 이 있는 경우는 쪼개지지 않은 최소 길이).

        //[중요!!!]{*****************************************************************
        //저장후 1 Byte 라도 여유가 있고 문자열 끝까지 처리한 경우는 종료.
        //
        //단, [한글] 의 경우는 [쪼개짐] 을 방지하기 위하여 [쪼개짐] 위치의 [한글] 을
        //버리게 되므로 1 바이트 여유가 발생해도 문자열을 다 처리하지 않은 상태일수
        //있으므로 반드시 [문자열:완료] 도 같이 확인.
        //}**************************************************************************

        if(((u + r + 1) < b) && ((i + r) >= l))
        {
          //문자열 을 모두 처리한것.
          break;

        }
        else
        {
          //[저장소] 처음부터 다시 저장.
          u = 0;

          //문자열에서 다음 읽어들일 위치.
          i += r;

          //[행:단위 끊기]
          //{
              //[!]{-----------------------------------------------
              //[행:단위] 로 출력하여 보기 좋게 유지.
              //현재 <i> 가 존재하는 행부터 다시 처리한다.
              //출력시 <i> 가 위치한 행처음부터 다시 출력된다.
              //이전 문자열은 실제 출력되지 않기 때문에 최종적으로
              //출력되는 부분에만 적용.
              //}--------------------------------------------------

              //현재 행의 첫부분부터 다시 출력.
              i = STR_Get_ThisLineStartIndex(pStr, i, NULL);

          //}

        }

      }

      //[저장소] 사용량 기록(저장된 문자열 길이와 동일).
      _buf_msgSize = u + r;

    } break;

    case  d_msg_debug :
    {
      //[전처리]
      //{
          if(pClearAdd == true)
          {
            _buf_debug[0]  = '\0';

            _buf_debugSize = 0;

          }

      //}

      b = OPT_DebugBufSize;

      //현재 저장돼 있는 크기가 저장 시작 위치.
      u = _buf_debugSize;

      i = 0;

      while(1)
      {
        //빈공간 크기 얻기.
        e = b - u;

        //문자열 끝까지만 처리-----------------v
        //'\0' 공간-----------------------v
        r = STR_SetLength(&(pStr[i]), e - 1, '\0', &(_buf_debug[u]));
        //<r> 은 처리된 문자열 길이([한글] 이 있는 경우는 쪼개지지 않은 최소 길이).

        //[중요!!!]{*****************************************************************
        //저장후 1 Byte 라도 여유가 있고 문자열 끝까지 처리한 경우는 종료.
        //
        //단, [한글] 의 경우는 [쪼개짐] 을 방지하기 위하여 [쪼개짐] 위치의 [한글] 을
        //버리게 되므로 1 바이트 여유가 발생해도 문자열을 다 처리하지 않은 상태일수
        //있으므로 반드시 [문자열:완료] 도 같이 확인.
        //}**************************************************************************

        if(((u + r + 1) < b) && ((i + r) >= l))
        {
          //문자열 을 모두 처리한것.
          break;

        }
        else
        {
          //[저장소] 처음부터 다시 저장.
          u = 0;

          //문자열에서 다음 읽어들일 위치.
          i += r;

          //[행:단위 끊기]
          //{
              //[!]{-----------------------------------------------
              //[행:단위] 로 출력하여 보기 좋게 유지.
              //현재 <i> 가 존재하는 행부터 다시 처리한다.
              //출력시 <i> 가 위치한 행처음부터 다시 출력된다.
              //이전 문자열은 실제 출력되지 않기 때문에 최종적으로
              //출력되는 부분에만 적용.
              //}--------------------------------------------------

              //현재 행의 첫부분부터 다시 출력.
              i = STR_Get_ThisLineStartIndex(pStr, i, NULL);

          //}

        }

      }

      //[저장소] 사용량 기록(저장된 문자열 길이와 동일).
      _buf_debugSize = u + r;

    } break;

  }

}

void __fastcall Tmsg_msg_Form::_Print(int    pTEXTindex,
                                      char  *pSTR)
{
  //[2006.11.02.목][생성!!!]{-------------------------------------------------------------
  //전달받은 문자열을 [관리 버퍼] 에 할당한다음 내용을 출력한다.
  //
  //[2009.04.24.금][참고!!!]{-------------------------------------------------------------
  //이 함수는 항상 [저장소] 처음부터 일괄 저장하므로 _BufOvf() 함수를 사용할 칠요는 없다.
  //
  //[2009.05.14.목][추가!!!]--------------------------------------------------------------
  //대상 알림창이 보이지 않는 경우는 보이게 만들고 시작한다.
  //
  //[2011.08.21.일][수정!!!]--------------------------------------------------------------
  //}-------------------------------------------------------------------------------------

  //[안전장치][2012.06.25.월][추가!!!]{---
  if(ide_msg_Form == NULL) return;
  //}-------------------------------------

  //[대상 보이기]
  //{
      //[2009.05.14.목][추가!!!]{--------------------------
      //[출력 대상이 보이지 않는 경우는 보이게 만들어준다.
      //}--------------------------------------------------

      if(pTEXTindex != _text_index)
      {
        //강제로 보이게 만든다.
        ide_msg_Form->_tabs_Form->_TabIndex(pTEXTindex);

      }

  //}

  //[문자열 저장]
  //{
      //[저장소 초기화]
      //{
          //[2011.08.21.일][중요수정!!!]{---------------------------------------------
          //<_Print()> 함수는 항상 [저장소] 를 새로 채우고 시작하므로 [저장소] 자체를
          //새로 초기화 하고 처리해야 한다.
          //}-------------------------------------------------------------------------

          //현재 [저장소] 를 초기화 하고 새로 처음부터 다시 저장한다.
          _buf_msg[0]  = '\0';
          _buf_msgSize = 0;

      //}

      //[2009.04.24.금][수정!!!]{------------------------------------------
      //[저장소] 용량을 고려하는 함수를 사용하여 처리하는 것으로 수정한다.
      _BufAdd(pTEXTindex, true, pSTR);
      //STR_Assign(_buf[pTEXTindex], pSTR);
      //}------------------------------------------------------------------

  //}

  //[표시 할 것인가?]
  //{
      //[2006.12.12.화][추가!!!]{-------------------------------------------
      //추가하는 문자열이 대상이 되는 [문서상자] 가 보이지 않는 탭의 경우는
      //문자열만 추가하고 출력하지는 않아야 한다.
      //}-------------------------------------------------------------------

      if(pTEXTindex != _text_index) return;

  //}

  //[문자열 출력]
  //{
      _Text(pTEXTindex);

  //}

  //[스크롤 수정][2006.12.10.일][추가!!!]
  //{
      //출력 문자열의 양이 수정된 경우는 스크롤을 다시 그려주어야 한다.
      _Scroll_Set();

  //}

  return;

}

void __fastcall Tmsg_msg_Form::_PrintAdd(int    pTEXTindex,
                                         char  *pSTR)
{
  //[2006.11.02.목][생성!!!]{------------------------------------
  //전달받은 문자열을 [관리 버퍼] 의 문자열에 추가한뒤 출력한다.
  //
  //[2009.05.14.목][추가!!!]-------------------------------------
  //대상 알림창이 보이지 않는 경우는 보이게 만들고 시작한다.
  //}------------------------------------------------------------

  //[VAR]
  //{
      int  scroll_max;

  //}

  //[안전장치][2012.06.25.월][추가!!!]{---
  if(ide_msg_Form == NULL) return;
  //}-------------------------------------

  //[대상 보이기]
  //{
      //[2009.05.14.목][추가!!!]{--------------------------
      //[출력 대상이 보이지 않는 경우는 보이게 만들어준다.
      //}--------------------------------------------------

      if(pTEXTindex != _text_index)
      {
        //강제로 보이게 만든다.
        ide_msg_Form->_tabs_Form->_TabIndex(pTEXTindex);

      }

  //}

  //[문자열 저장]
  //{
      //STR_Add(_buf[pTEXTindex], pSTR);

      //[2009.04.24.금][수정!!!]{------------------------------------------
      //[저장소] 용량을 고려하는 함수를 사용하여 처리하는 것으로 수정한다.
      _BufAdd(pTEXTindex, false, pSTR);
      //}------------------------------------------------------------------

  //}

  //[표시 할 것인가?]
  //{
      //[2006.12.12.화][추가!!!]{-------------------------------------------
      //추가하는 문자열이 대상이 되는 [문서상자] 가 보이지 않는 탭의 경우는
      //문자열만 추가하고 출력하지는 않아야 한다.
      //}-------------------------------------------------------------------

      if(pTEXTindex != _text_index) return;

  //}

  //[문자열 출력]
  //{
      _Text(pTEXTindex);

  //}

  //[스크롤 수정]
  //{
      //출력 문자열의 양이 수정된 경우는 스크롤을 다시 그려주어야 한다.
      _Scroll_Set();

  //}

  //[마지막으로 스크롤]
  //{
      //문자열을 추가한 경우는 가장 마지막에 추가한 부분을 보여 주어야 한다.
      scroll_max = ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_max;
      ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_Position(scroll_max);

  //}

  return;

}

void __fastcall Tmsg_msg_Form::_PrintAddLine(int    pTEXTindex,
                                             char  *pSTR)
{
  //[2006.11.02.목][생성!!!]{------------------------------------
  //전달받은 문자열을 [관리 버퍼] 의 문자열에 추가한뒤 출력한다.
  //단, 행단위로 추가한다.
  //
  //[2009.05.14.목][추가!!!]-------------------------------------
  //대상 알림창이 보이지 않는 경우는 보이게 만들고 시작한다.
  //}------------------------------------------------------------

  //[VAR]
  //{
      int  scroll_max;
      
  //}

  //[안전장치][2012.06.25.월][추가!!!]{---
  if(ide_msg_Form == NULL) return;
  //}-------------------------------------

  //[대상 보이기]
  //{
      //[2009.05.14.목][추가!!!]{--------------------------
      //[출력 대상이 보이지 않는 경우는 보이게 만들어준다.
      //}--------------------------------------------------

      if(pTEXTindex != _text_index)
      {
        //강제로 보이게 만든다.
        ide_msg_Form->_tabs_Form->_TabIndex(pTEXTindex);

      }

  //}

  //[문자열 저장]
  //{
      //지금 추가하는 문자열이 처음 문자열인 경우는 CRLF 를 추가하지 않는다.
      if(_buf[pTEXTindex][0] != '\0')
      {
        //행을 바꾸기 위하여 CRLF 를 앞에 추가해 준다.
        //STR_Add(_buf[pTEXTindex], "\r\n");

        //[2009.04.24.금][수정!!!]{------------------------------------------
        //[저장소] 용량을 고려하는 함수를 사용하여 처리하는 것으로 수정한다.
        _BufAdd(pTEXTindex, false, "\r\n");
        //}------------------------------------------------------------------

      }

      //새로운 행에 문자열을 추가한다.
      //STR_Add(_buf[pTEXTindex], pSTR);

      //[2009.04.24.금][수정!!!]{------------------------------------------
      //[저장소] 용량을 고려하는 함수를 사용하여 처리하는 것으로 수정한다.
      _BufAdd(pTEXTindex, false, pSTR);
      //}------------------------------------------------------------------
      
  //}

  //[표시 할 것인가?]
  //{
      //[2006.12.12.화][추가!!!]{-------------------------------------------
      //추가하는 문자열이 대상이 되는 [문서상자] 가 보이지 않는 탭의 경우는
      //문자열만 추가하고 출력하지는 않아야 한다.
      //}-------------------------------------------------------------------

      if(pTEXTindex != _text_index) return;
  //}

  //[문자열 출력]
  //{
      _Text(pTEXTindex);
  //}

  //[스크롤 수정]
  //{
      //출력 문자열의 양이 수정된 경우는 스크롤을 다시 그려주어야 한다.
      _Scroll_Set();
  //}

  //[마지막으로 스크롤]
  //{
      //문자열을 추가한 경우는 가장 마지막에 추가한 부분을 보여 주어야 한다.
      scroll_max = ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_max;
      ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_Position(scroll_max);
  //}

  return;

}

void __fastcall Tmsg_msg_Form::_Scroll_Set(void)
{
  //[2006.11.29.수][생성!!!]{---------------------------------------
  //문서량에 따라 scrollbar 를 재설정한다.
  //단, 현재 보이는 영역의 문서는 스크롤 대상이 아니므로 제외 한다.
  //
  //[2009.05.14.목][수정!!!]----------------------------------------
  //가장 아래에 출력된 행이 영역 아래에 겹치지 않도록 처리한다.
  //}---------------------------------------------------------------

  //[VAR]
  //{
      //표시 영역의 충 줄수.
      int  view_line = 0;

      //스크롤되는 총 줄수.(표시 영역 밖의 문서의 총 행수가 된다.)
      int  scroll_line = 0;

      //순수한 문서 전체 행수.
      int  total_line  = 0;

  //}

  //[안전장치][2012.06.25.월][추가!!!]{---
  if(ide_msg_Form == NULL) return;
  //}-------------------------------------

  //[검사]{------------------------
  if(this->Parent == NULL) return;
  //}------------------------------

  //[계산]
  //{
      //문서를 보여주는 영역의 행수를 구한다.
      view_line   = (this->Height - ((Tide_msg_Form *)(this->Parent))->_tabs_Form->Height) / _line_height;

      //전체 문서 행수를 구한다.
      ////[2009.05.14.목][수정!!!]{----------------------------------------------
      //맨 아래의 출력행이 아래 영역 끝에서 잘리지 않고 행전체가 표시될수 있도록
      //줄이동자를 1행 여유있게 설정한다.------------------v
      total_line  = STR_Get_LineCount(_buf[_text_index]) + 1;
      //}------------------------------------------------------------------------

      //스크롤 되는 문서의 행수를 구한다.
      scroll_line = total_line - view_line;

      //만일 모든 문서가 표시 영역에 있는 경우는 scroll 되는 양은 없다.
      if(scroll_line < 0)
      {
        scroll_line = 0;

      }
  //}

  //[수직 스크롤바 설정]
  //{
      //[주의!!!][2006.11.30.목]{----------------------------------------------------------
      //<thumb> 크기는 항상 문서 총량의 1/4 크기를 갖도록 비율을 고정한다.
      //순수하게 <보이는행 / 전체 문서행> 의 비율을 사용하는 경우, 전체 문서행이 너무 커서
      //보이는 문서행이 상대적으로 너무 작은 경우는 <thumb> 가 아예 보이지 않게 된다.
      //1/4 의 비율이 가장 보기 좋고 동작이 용이하다.
      //}----------------------------------------------------------------------------------

      //현재 보이는 영역의 행수.
      ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_DesignSize(total_line / 4);

      //스크롤 될 문서의 총 행수.
      ((Tide_msg_Form *)(this->Parent))->_scroll_v_Form->_Max(scroll_line);

  //}

  return ;

}

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

void __fastcall Tmsg_msg_Form::FormMouseWheel(TObject *Sender,
      TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
  //[2006.11.04.토][생성!!!]{---------------------------------------------
  //휠이 동작하는 경우는 _position 의 값을 1 씩 변화 시킨다.
  //WheelDelta 는 변화값이나 자체에 큰 의미는 없으므로 위/아래 어느쪽으로
  //휠이 움직였는지 확인하는 정도로 사용하고 값을 사용하지는 않는다.
  //}---------------------------------------------------------------------

  //[안전장치][2012.06.25.월][추가!!!]{---
  if(ide_msg_Form == NULL) return;
  //}-------------------------------------

  //[주의!!!]
  //{
      //---------------------------------------------------------------
      //반드시 true 로 설정하여 순수하게 직접 컨트롤 할수 있도록 한다.
      //그렇지 않은 경우 한번 스크롤시 3 번정도 이 함수가 호출되므로
      //원치 않는 동작이 생긴다.
      Handled = true;
      //이제 정확하게 스크롤 한 단계마다 이 함수는 한번씩 call 된다.
      //---------------------------------------------------------------
  //}

  //[휠동작]
  //{
      //_position 값을 수정하고 자동으로 다시 scrollbar 를 그려준다.
      if     (WheelDelta > 0)
      {
        ide_msg_Form->_scroll_v_Form->_position -= 3;
        ide_msg_Form->_scroll_v_Form->_Position(ide_msg_Form->_scroll_v_Form->_position);

      }
      else if(WheelDelta < 0)
      {
        ide_msg_Form->_scroll_v_Form->_position += 3;
        ide_msg_Form->_scroll_v_Form->_Position(ide_msg_Form->_scroll_v_Form->_position);

      }
  //}

  return;

}

void __fastcall Tmsg_msg_Form::FormMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
  //[2006.11.04.토][생성!!!]

  //[촛점주기]
  //{
      //[휠마우스] 를 사용하게 하기 위하여 반드시 포커스를 주어야 한다.
      if(this->Focused() != true)
      {
        this->SetFocus();

      }
  //}

  return;

}

//------------------------------------------------------------------------------
//[배경화면관련]----------------------------------------------------------------
//------------------------------------------------------------------------------

void __fastcall Tmsg_msg_Form::_BACKBMP_Brightness(int  pBrightness)
{
  //[2007.10.05.금][생성!!!]{----
  //바탕 그림의 밝기를 조정한다.
  //}----------------------------

  //[VAR]
  //{
      AnsiString  _bmp_path;

  //}

  //[배경화면]
  //{
      //[그림 경로]
      //{
          if(IDE_BACKBMP_entire)
          {
            //한개의 그림을 전체영역으로 사용하는 경우.
            _bmp_path = (AnsiString)_ide_option->ideBackpicturePath;

            //[확인]
            //[
                //[2007.12.04.화][추가!!!]
                //그림이 있는지 먼저 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //그림이 존재하지 않는 경우는 기본 그림으로 대체한다.
                  _bmp_path = IDE_BACKBMP_entire_path;

                }

                //기본 그림이 있는지 한번더 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //기본 그림 역시 존재하지 않는다면 그냥 표시하지 않는다.
                  _bmp_path = "";

                }

            //}

          }
          else
          {
            //지정된 전용 그림을 사용한다.
            _bmp_path = (AnsiString)_ide_option->msgBackPicturePath;

            //[확인]
            //[
                //[2007.12.04.화][추가!!!]
                //그림이 있는지 먼저 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //그림이 존재하지 않는 경우는 기본 그림으로 대체한다.
                  _bmp_path = IDE_BACKBMP_msg_path;

                }

                //기본 그림이 있는지 한번더 확인한다.
                if(FileExists(_bmp_path) != true)
                {
                  //기본 그림 역시 존재하지 않는다면 그냥 표시하지 않는다.
                  _bmp_path = "";

                }

            //}

          }

      //}

      //[그림 확인]
      //{
          //[2007.12.04.화][추가!!!]
          //만일 그림이 없는 경우는 처리하지 않는다.
          if(_bmp_path == "")
          {
            //이 경우는 배경을 전부 흰색으로 칠해 주어야 한다.

            //크기지정.
            _bmp_back_->Width  = Screen->Width;
            _bmp_back_->Height = Screen->Height;

            //색칠하기.
            _bmp_back_->Canvas->Brush->Color = clWhite;
            _bmp_back_->Canvas->FillRect(_bmp_back_->Canvas->ClipRect);

          }
          else
          {
            //그림 읽어 들이기.
            BMP_LoadJpeg(_bmp_back_, _bmp_path, Screen->Width, Screen->Height, d_BMP_load_tile);

          }

      //}

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

      //배경 그림을 밝게 하여 문자가 잘 보기게 만든다.
      BMP_Brightness(_bmp_back_, _ide_option->msg_back_brightness);

  //}

  //[다시 그려서 보여주기]
  //{
      _Text(_text_index);

  //}

  return;

}

void __fastcall Tmsg_msg_Form::_BACKBMP_ChangeJpeg(AnsiString  pJpegFilePath)
{
  //[2007.12.02.일][생성!!!]{----------------
  //바탕 그림을 지정 그림으로 다시 그려준다.
  //}----------------------------------------

  //그림 읽어 들이기.
  BMP_LoadJpeg(_bmp_back_, pJpegFilePath, Screen->Width, Screen->Height, d_BMP_load_tile);

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

  //배경 그림을 밝게 하여 문자가 잘 보기게 만든다.
  BMP_Brightness(_bmp_back_, _ide_option->msg_back_brightness);

  //[다시 그려서 보여주기]
  //{
      _Text(_text_index);

  //}

  return;

}

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

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

  switch(Button)
  {
    case mbLeft :
    {




    } break;

    case mbRight :
    {
      //[2011.08.21.일][추가!!!]{------------------------------------------------------------
      //우측버튼 역시 현재는 사용하지 않으므로 현재 창의 모든 내용을 지우는 것으로 설정한다.
      //}------------------------------------------------------------------------------------

      _Print(_text_index, "");

    } break;

    case mbMiddle :
    {
      //[2009.10.02.금][추가!!!]{--------------------------
      //가운데 버튼인 경우는 현재 창의 모든 내용을 지운다.
      //}--------------------------------------------------

      _Print(_text_index, "");

    } break;

  }

  return;

}


