#include "ledit.h"

#define EC_EXIT     2000
#define EC_LOCKSUN  2001
#define EC_SLOW     2002

#ifdef WIN32
#define NOTIFY_CODE HIWORD(wParam)
#define COMMAND_CODE LOWORD(wParam)
#define SENDER_HWND (HWND)lParam
#else
#define NOTIFY_CODE HIWORD(lParam)
#define COMMAND_CODE wParam
#define SENDER_HWND (HWND)LOWORD(lParam)
#endif

static MSG Msg;
static WNDPROC OldProc;
static LONG XScreen;
static LONG YScreen;
static BOOL BitMapInUse = TRUE;
static BOOL SunLocked = FALSE;
static LONG XSun = 0;
static LONG YSun = 1;
static HMENU Tools;

// Main window function
LRESULT CALLBACK _export FrameProc (HWND     Wnd,
				    UINT     Msg,
				    WPARAM     wParam,
				    LPARAM    lParam)
{
  switch (Msg)
    {
      case EM_DRAW:
	{
	  // Determine window rect
	  RECT R;
	  GetClientRect(Wnd,&R);

     // Retrieve DC
	  HDC DC = (HDC)wParam;
	  LRESULT LResult = 0;
	  HDC MemDC;
     HBITMAP BitMap;

	  // Involve bitmap if needed
	  if ( BitMapInUse )
	    {
	      MemDC = CreateCompatibleDC(DC);
	      if ( MemDC )
	        {
		  BitMap = CreateCompatibleBitmap(DC,R.right,R.bottom);
		  if ( BitMap )
		    {
            // Set result to return
		      LResult = (LRESULT)BitMap;

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

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

	  // Fill background
	  HBRUSH Brush = CreateSolidBrush(RGB(192,192,192));
	  FillRect(DC,&R,Brush);
	  DeleteObject(Brush);

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

              // Truncate values to 16-bit if they are large
	      if ( X > XScreen )
		X = XScreen;
	      if ( X < - XScreen)
                X = -XScreen;
	      if ( Y > YScreen )
		Y = YScreen;
	      if ( Y < - YScreen)
		Y = -YScreen;

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

	  // Draw ellipse
	  Brush = SelectObject(DC,CreateSolidBrush(RGB(255,255,0)));
	  HPEN 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 )
	    {
	      SelectObject(MemDC,BitMap);
              DeleteDC(MemDC);
            }

          // Return value that was prepared
	  return LResult;
	}
      case WM_COMMAND:
        {
	  switch (wParam)
	    {
	      case EC_DEFAULT_LEDIT_ID:
                // Don't send LEdit notifications back;
	        return 0;

	      case EC_EXIT:
	        {
                  // Exit command
		  SendMessage(Wnd,WM_CLOSE,0,0L);
                  return 0;
	        }
	      case EC_LOCKSUN:
		{
		  // Lock the Sun command
		  if ( SunLocked )
		    {
                      // Uncheck menu item
		      CheckMenuItem(Tools,EC_LOCKSUN,MF_BYCOMMAND
		        | MF_UNCHECKED);

		      // Redraw window
		      InvalidateRect(Wnd,NULL,FALSE);
                    }
		  else
		    {
                      // Check menu item
		      CheckMenuItem(Tools,EC_LOCKSUN,MF_BYCOMMAND
		        | MF_CHECKED);

		      // Store the place where Sun is locked
		      YSun = SendMessage(Wnd,EM_GETFIRSTVISIBLELINE,0,0L);
	              XSun = SendMessage(Wnd,EM_GETHORZPOSITION,0,0L);
                    }
		  SunLocked = !SunLocked;
                  return 0;
		}
	      case EC_SLOW:
		{
		  // Slow But No Blink command
		  BitMapInUse = !BitMapInUse;

                  // Check/Uncheck menu item
		  CheckMenuItem(Tools,EC_SLOW,MF_BYCOMMAND | (BitMapInUse) ?
		    MF_CHECKED : MF_UNCHECKED);
                  return 0;
                }
            }
          break;
        }
      case WM_DESTROY:
	{
	  // Stop the application
	  PostQuitMessage(0);
	  break;
        }
    }
  // Call LEdit Window Proc() for all the messages
  return OldProc(Wnd,Msg,wParam,lParam);
}

// Main Windows function
#pragma argsused
int PASCAL WinMain (HINSTANCE hInstance,
		    HINSTANCE hPrevInst,
		    LPSTR     lpszCmdLine,
		    int       nCmdShow)

{
  // To ensure static loading of LEDIT.DLL
  LVer();

  // Set constants
  XScreen = GetSystemMetrics(SM_CXSCREEN);
  YScreen = GetSystemMetrics(SM_CYSCREEN);

  // Create main window
  HWND Wnd = CreateWindow(LEDIT_CLASS,
			  "Subclassed LEdit",
			  WS_OVERLAPPEDWINDOW | ES_HASMENU | ES_BIGINDENT
			  | WS_HSCROLL | WS_VSCROLL | ES_LOADFROMPARAM
			  | ES_TRANSPARENT | ES_CANCHANGEFONT,
			  CW_USEDEFAULT, CW_USEDEFAULT,
			  CW_USEDEFAULT, CW_USEDEFAULT,
			  0, 0, hInstance,
			  "LEdit-File-Init-ledit_5.cpp");
  if ( Wnd )
    {
      // Ensure 16-bit and 32-bit compatibility
      SendMessage(Wnd,EM_SETRUNTIMEFLAGS,EMP_16_AS32,0);

      // Change a little LEdit behaviour
      SendMessage(Wnd,EM_SETFONT,(WPARAM)
        GetStockObject(DEVICE_DEFAULT_FONT),0L);
      SendMessage(Wnd,EM_SETSYNTAX,0,1);
#include "ledit__s.inc"

      // Change menu. Note that popup-menu changes too.
      HMENU Menu = (HMENU)SendMessage(Wnd,EM_GETHANDLE,EMP_32_MENU,0L);
      HMENU Edit = GetSubMenu(Menu,0);
      Tools = GetSubMenu(Menu,2);
      AppendMenu(Edit,MF_SEPARATOR,0,NULL);
      AppendMenu(Edit,0,EC_EXIT,"E&xit\bAlt+F4");
      AppendMenu(Tools,MF_SEPARATOR,0,NULL);
      AppendMenu(Tools,0,EC_LOCKSUN,"&Lock The Sun");
      AppendMenu(Tools,MF_CHECKED,EC_SLOW,"Slow But No &Blink");

      // Subclass window
      OldProc = (WNDPROC) GetWindowLong(Wnd,GWL_WNDPROC);
      SetWindowLong(Wnd,GWL_WNDPROC,(LONG) FrameProc);

      // Bind LEdit messages to itself
      SendMessage(Wnd,EM_SETHANDLE,0,(LPARAM)Wnd);

      // Show window
      ShowWindow(Wnd,SW_SHOW);

      // Run message loop
      while ( GetMessage(&Msg,0,0,0) )
	{
	  TranslateMessage(&Msg);
	  DispatchMessage(&Msg);
	}
    }
return 0;
}