// =================================================
// Определения
// =================================================

#define INCL_WIN
#define INCL_GPI
#define INCL_WINDIALOGS
#include <os2.h>
#include <stdio.h>
#include "mousemov.h"

// Прототип функции окна приложения
MRESULT EXPENTRY WndProc(HWND, ULONG, MPARAM, MPARAM);

// =================================================
// Глобальные переменные
// =================================================

HAB  hab;
HWND hWndFrame;
HWND hWndClient;

CHAR szAppTitle[] = "Mouse Mover";

// Координаты курсора мыши в момент нажатия
// левой клавиши мыши
SHORT cxPoint;
SHORT cyPoint;

// Координаты курсора мыши в момент отпускания
// леовой клавиши мыши
SHORT cxNewPoint;
SHORT cyNewPoint;

// Признак начала процесса перемещения окна
BOOL  fDrag = FALSE;

// Текст, который будет отображаться в окне
CHAR pszText[] =
  "Перемещайте окно при помощи левой клавиши мыши";

// Идентификаторы указателей мыши
HPOINTER hptr, hptr1;

// =================================================
// Главная функция приложения main
// =================================================

int main()
{
  HMQ   hmq;
  QMSG  qmsg;
  BOOL  fRc;

  // Флаги для создания окна Frame Window
  // Мы не создаем окна заголовка, системного меню,
  // а также окна кнопок минимизации и максимизации
  ULONG flFrameFlags = FCF_SIZEBORDER |
    FCF_SHELLPOSITION | FCF_TASKLIST | FCF_ICON;

  // Имя класса главного окна
  CHAR  szWndClass[] = "MOUSEMOV";

  hab = WinInitialize(0);
  if(hab == NULLHANDLE)
  {
    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка инициализации",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    return(-1);
  }

  // Создаем очередь сообщений
  hmq = WinCreateMsgQueue(hab, 0);
  if(hmq == NULLHANDLE)
  {
    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании очереди сообщений",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinTerminate(hab);
    return(-1);
  }

  // Регистрация главного окна приложения
  fRc = WinRegisterClass(hab, szWndClass,
    (PFNWP)WndProc, 0, 0);
  if(fRc == FALSE)
  {
    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при регистрации класса главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinDestroyMsgQueue(hmq);
    WinTerminate(hab);

    return(-1);
  }

  // Создаем главное окно приложения
  hWndFrame = WinCreateStdWindow (HWND_DESKTOP,
    WS_VISIBLE,
    &flFrameFlags, szWndClass, szAppTitle,
    0, 0, ID_APP_FRAMEWND, &hWndClient);
  if(hWndFrame == NULLHANDLE)
  {
    WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
      "Ошибка при создании главного окна",
      "Ошибка", 0, MB_ICONHAND | MB_OK);
    WinDestroyMsgQueue(hmq);
    WinTerminate(hab);

    return(-1);
  }

  while(WinGetMsg(hab, &qmsg, 0, 0, 0))
    WinDispatchMsg(hab, &qmsg);

  WinDestroyWindow(hWndFrame);
  WinDestroyMsgQueue(hmq);
  WinTerminate(hab);
  return(0);
}

// =================================================
// Функция главного окна приложения
// =================================================

MRESULT EXPENTRY
WndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  HPS hps;
  POINTL ptl;
  RECTL rec;
  SWP swp;

  switch (msg)
  {
    // При создании окна загружаем указатели мыши
    case WM_CREATE:
    {
      hptr  = WinLoadPointer(HWND_DESKTOP,
        NULLHANDLE, ID_APP_POINTER);
      hptr1 = WinLoadPointer(HWND_DESKTOP,
        NULLHANDLE, ID_APP_POINTER1);
      return FALSE;
    }

    // При уничтожении окна удаляем указатели мыши
    case WM_DESTROY:
    {
      WinDestroyPointer(hptr);
      WinDestroyPointer(hptr1);
      return 0;
    }

    // Когда пользователь нажимает левую клавишу
    // мыши, запоминаем координаты курсора и
    // выдвигаем окно приложения на передний план
    case WM_BUTTON1DOWN:
    {
      cxPoint = MOUSEMSG(&msg) -> x;
      cyPoint = MOUSEMSG(&msg) -> y;

      // Изменяем расположение окна по оси Z
      WinSetWindowPos(hWndFrame, HWND_TOP,
        0, 0, 0, 0, SWP_ZORDER);

      // Устанавливаем признак перемещения
      // главного окна приложения
      fDrag = TRUE;
      return 0;
    }

    // При отпускании левой клавиши мыши сбрасываем
    // признак перемещения окна
    case WM_BUTTON1UP:
    {
      // Сбрасываем признак перемещения
      // главного окна приложения
      fDrag = FALSE;
      return 0;
    }

    // Это сообщение приходит при перемещении курсора
    // мыши.
    case WM_MOUSEMOVE:
    {
      // Если включен признак перемещения, определяем
      // новые координаты курсора и передвигаем окно
      if(fDrag)
      {
        // Выбираем указатель в виде закрытой руки
        WinSetPointer(HWND_DESKTOP, hptr1);

        cxNewPoint = MOUSEMSG(&msg) -> x;
        cyNewPoint = MOUSEMSG(&msg) -> y;

        // Определяем текущие координаты окна
        WinQueryWindowPos(hWndFrame, &swp);

        // Передвигаем окно
        WinSetWindowPos(hWndFrame, HWND_TOP,
          swp.x + (cxNewPoint - cxPoint),
          swp.y + (cyNewPoint - cyPoint),
          0, 0, SWP_MOVE);
      }

      else
        // Выбираем указатель в виде открытой руки
        WinSetPointer(HWND_DESKTOP, hptr);

      return (MRESULT)TRUE;
    }

    // В ответ на сообщение WM_PAINT выводим
    // в центре окна строку текста
    case WM_PAINT:
    {
      // Получаем пространство отображения
      hps = WinBeginPaint(hWnd, NULLHANDLE, &rec);

      // Определяем размеры главного окна
      WinQueryWindowRect(hWnd, &rec);

      // Выводим текст в центре окна
      WinDrawText(hps, -1, pszText, &rec, 0L, 0L,
        DT_WORDBREAK | DT_CENTER | DT_VCENTER |
        DT_TEXTATTRS | DT_ERASERECT);

      // Освобождаем пространство отображения
      WinEndPaint(hps);
      return 0;
    }

    case WM_ERASEBACKGROUND:
      return(MRFROMLONG(1L));

    // При изменении размеров окна сохраняем новые
    // размеры и перерисовываем окно
    case WM_SIZE:
    {
      // При изменении размеров окна выполняем его
      // перерисовку
      WinInvalidateRect(hWnd, NULL, TRUE);
      return 0;
    }

    // Если пользователь сделал двойной щелчок левой
    // клавише мыши, завершаем работу приложения
    case WM_BUTTON1DBLCLK:
    {
      WinPostMsg(hWnd, WM_QUIT, 0L, 0L);
      return 0;
    }

    default:
      return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  }
}


