uses WinTypes, WinProcs, Win31, LEdit;
{$I LEDIT__S.INC}

const
  EC_EXIT    = 2000;
  EC_LOCKSUN = 2001;
  EC_SLOW    = 2002;
  BitMapInUse: boolean = TRUE;
  SunLocked: boolean = FALSE;
  XSun: longint = 0;
  YSun: longint = 1;

var
  Msg: TMsg;
  Wnd: hWnd;
  OldProc: function(Wnd,Msg,wParam: word; lParam: longint): longint;
  XScreen,
  YScreen: longint;
  Menu, Edit, Tools: hMenu;

{ Main window function }
function FrameProc (Wnd:    hWnd;
		    Msg,
		    wParam: word;
		    lParam: longint): longint;
export;

var
  R: TRect;
  DC, MemDC: hDC;
  BitMap: hBitMap;
  Brush: hBrush;
  Pen: hPen;
  X,Y,Units: longint;

begin
  case Msg of
    EM_DRAW:
      begin
      	{ Determine window rect }
	GetClientRect(Wnd,R);

        { Retrieve DC }
	DC := wParam;
        FrameProc := 0;

	{ Involve bitmap if needed }
	if BitMapInUse then
	  begin
	    MemDC := CreateCompatibleDC(DC);
	    if MemDC <> 0 then
	      begin
		BitMap := CreateCompatibleBitmap(DC,R.right,R.bottom);
		if BitMap <> 0 then
		  begin
                    { Set result to return }
		    FrameProc := MAKELONG(BitMap,EMF_DELETEBITMAP);

		    { Select the bitmap in MemDC and retrieve }
                    { the handle of previous bitmap           }
		    BitMap := SelectObject(MemDC,BitMap);

                    { Bind all drawing to MemDC }
                    DC := MemDC;
		  end
		else
		  begin
                    { We need not MemDC if we haven't got any bitmap }
                      DeleteDC(MemDC);
                      MemDC := 0;
                  end;
              end;
	  end
	else
          MemDC := 0;

	{ Fill background }
	Brush := CreateSolidBrush(RGB(192,192,192));
	FillRect(DC,R,Brush);
	DeleteObject(Brush);

	if SunLocked then
          begin
	    { Retrieve info on scrolling position }
	    Y := SendMessage(Wnd,EM_GETFIRSTVISIBLELINE,0,0) - YSun;
	    X := SendMessage(Wnd,EM_GETHORZPOSITION,0,0) - XSun;
	    Units := SendMessage(Wnd,EM_GETUNITS,0,0);
	    X := X * LOWORD(Units);
	    Y := Y * HIWORD(Units);

            { Truncate values to 16-bit if they are large }
	    if X > XScreen then
	      X := XScreen;
	    if X < - XScreen then
              X := -XScreen;
	    if Y > YScreen then
	      Y := YScreen;
	    if Y < - YScreen then
	      Y := -YScreen;

	    { Move ellipse rectangle according to scrolling }
	    OffsetRect(R, -X, -Y);
	  end;

	{ Draw ellipse }
	Brush := SelectObject(DC,CreateSolidBrush(RGB(255,255,0)));
	Pen := SelectObject(DC,GetStockObject(NULL_PEN));
	Ellipse(DC,R.left,R.top,R.right,R.bottom);
	SelectObject(DC,Pen);
	DeleteObject(SelectObject(DC,Brush));

	{ Delete memory DC if it exists }
	if MemDC <> 0 then
	  begin
	    SelectObject(MemDC,BitMap);
            DeleteDC(MemDC);
          end;

        { Return }
        exit;
      end;
    WM_COMMAND:
      begin
	case wParam of
	  EC_DEFAULT_LEDIT_ID:
            begin
              { Don't send LEdit notifications back; }
              FrameProc := 0;
	      exit;
            end;
	  EC_EXIT:
	    begin
              { Exit command }
	      SendMessage(Wnd,WM_CLOSE,0,0);
              exit;
	    end;
	  EC_LOCKSUN:
	    begin
	      { Lock the Sun command }
	      if SunLocked then
		begin
                  { Uncheck menu item }
		  CheckMenuItem(Tools,EC_LOCKSUN,MF_BYCOMMAND
                    OR MF_UNCHECKED);

		  { Redraw window }
		  InvalidateRect(Wnd,nil,FALSE);
                end
	      else
		begin
                  { Check menu item }
		  CheckMenuItem(Tools,EC_LOCKSUN,MF_BYCOMMAND OR MF_CHECKED);

		  { Store the place where Sun is locked }
		  YSun := SendMessage(Wnd,EM_GETFIRSTVISIBLELINE,0,0);
	          XSun := SendMessage(Wnd,EM_GETHORZPOSITION,0,0);
                end;
	      SunLocked := NOT SunLocked;
              exit;
	    end;
	  EC_SLOW:
	    begin
	      { Slow But No Blink command }
	      BitMapInUse := NOT BitMapInUse;

              { Check/Uncheck menu item }
              if BitMapInUse then
	        CheckMenuItem(Tools,EC_SLOW,MF_BYCOMMAND OR MF_CHECKED)
              else
                CheckMenuItem(Tools,EC_SLOW,MF_BYCOMMAND OR MF_UNCHECKED);
              exit;
            end;
        end;
      end;
    WM_DESTROY:
      { Stop the application }
      PostQuitMessage(0);
  end;
  { Call LEdit Window Proc() for all the messages }
  FrameProc := OldProc(Wnd,Msg,wParam,lParam);
end;

{ Main block }
begin
  { Set constants }
  XScreen := GetSystemMetrics(SM_CXSCREEN);
  YScreen := GetSystemMetrics(SM_CYSCREEN);

  { Create main window }
  Wnd := CreateWindow('LEdit',
		      'Subclassed LEdit',
		      WS_OVERLAPPEDWINDOW OR ES_HASMENU OR ES_BIGINDENT
		      OR WS_HSCROLL OR WS_VSCROLL OR ES_LOADFROMPARAM
		      OR ES_TRANSPARENT OR ES_CANCHANGEFONT,
		      CW_USEDEFAULT, CW_USEDEFAULT,
		      CW_USEDEFAULT, CW_USEDEFAULT,
		      0, 0, hInstance,
		      PChar('LEdit-File-Init-ledit_5.cpp'));
  if Wnd <> 0 then
    begin
      { Change a little LEdit behaviour }
      SendMessage(Wnd,EM_SETFONT,GetStockObject(DEVICE_DEFAULT_FONT),0);
      SendMessage(Wnd,EM_SETSYNTAX,0,1);
      Behaviour(Wnd);

      { Change menu. Note that popup-menu changes too. }
      Menu := LOWORD(SendMessage(Wnd,EM_GETHANDLE,EMP_MENU,0));
      Edit := GetSubMenu(Menu,0);
      Tools := GetSubMenu(Menu,2);
      AppendMenu(Edit,MF_SEPARATOR,0,nil);
      AppendMenu(Edit,0,EC_EXIT,'E&xit'#08'Alt+F4');
      AppendMenu(Tools,MF_SEPARATOR,0,nil);
      AppendMenu(Tools,0,EC_LOCKSUN,'&Lock The Sun');
      AppendMenu(Tools,MF_CHECKED,EC_SLOW,'Slow But No &Blink');

      { Subclass window }
      @OldProc := TFarProc(GetWindowLong(Wnd,GWL_WNDPROC));
      SetWindowLong(Wnd,GWL_WNDPROC,longint(@FrameProc));

      { Bind LEdit messages to itself }
      SendMessage(Wnd,EM_SETHANDLE,0,MAKELONG(Wnd,0));

      { Show window }
      ShowWindow(Wnd,SW_SHOW);

      { Run message loop }
      while GetMessage(Msg,0,0,0) do
	begin
	  TranslateMessage(Msg);
	  DispatchMessage(Msg);
	end;
    end;
end.