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

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

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

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

HAB  hab;
HWND hWndFrame;
HWND hWndClient;

CHAR szAppTitle[] = "Clock Application";

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

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

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

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

// Размеры символов выбранного шрифта
SHORT cxChar, cyChar, cyDesc;

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

int main()
{
  HMQ   hmq;
  QMSG  qmsg;
  BOOL  fRc;
  FONTMETRICS fm;
  HPS hps;

  // Флаги для создания окна Frame Window.
  // Окно не имеет орагнов управления и
  // рамки для изменения размеров
  ULONG flFrameFlags = FCF_TASKLIST | FCF_ICON;

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

  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);
  }

  // Получаем пространство отображения
  hps = WinGetPS(hWndFrame);

  // Выбираем в пространство отображения шрифт
  // с фиксированной шириной символов
  SetCourierFont(hps);

  // Определяем метрики шрифта
  GpiQueryFontMetrics(hps, (LONG)sizeof(fm), &fm);

  cxChar = fm.lAveCharWidth;
  cyChar = fm.lMaxBaselineExt;
  cyDesc = fm.lMaxDescender;

  // Устанавливаем шрифт, выбранный в пространство
  // отображения по умолчанию
  ResetFont(hps);

  // Возвращаем пространство отображения
  WinReleasePS(hps);

  // Устанавливаем новые размеры и расположение
  // главного окна приложения
  WinSetWindowPos(hWndFrame, HWND_TOP,
    0, 0, 10 * cxChar, cyChar + cyDesc,
    SWP_SIZE | SWP_MOVE | SWP_ZORDER);

  // Запускаем цикл обработки сообщений
  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;
  RECTL rec;
  SWP   swp;
  CHAR  pszBuf[256];
  DATETIME dt;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Запускаем таймер с интервалом 1000 мс
      WinStartTimer(hab, hWnd, ID_APP_TIMER, 1000);

      // Загружаем идентификаторы курсоров мыши
      hptr  = WinLoadPointer(HWND_DESKTOP,
        NULLHANDLE, ID_APP_POINTER);

      hptr1 = WinLoadPointer(HWND_DESKTOP,
        NULLHANDLE, ID_APP_POINTER1);

      return FALSE;
    }

    case WM_DESTROY:
    {
      // Останавливаем таймер
      WinStopTimer(hab, hWnd, ID_APP_TIMER);

      // Удаляем курсоры мыши
      WinDestroyPointer(hptr);
      WinDestroyPointer(hptr1);
      return 0;
    }

    // Когда приходит сообщение от таймера,
    // перерисовываем главное окно приложения
    case WM_TIMER:
    {
      WinInvalidateRect(hWnd, NULL, TRUE);
      return 0;
    }

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

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

      // Определяем дату и время
      DosGetDateTime(&dt);

      sprintf(pszBuf, "%02d:%02d:%02d",
        dt.hours, dt.minutes, dt.seconds);

      // Устанавливаем шрифт для отображения
      SetCourierFont(hps);

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

      // Восстанавливаем шрифт
      ResetFont(hps);

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

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

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

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

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

      // Захватываем мышь
      WinSetCapture(HWND_DESKTOP, hWnd);
      return 0;
    }

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

      // Освобождаем мышь
      WinSetCapture(HWND_DESKTOP, NULLHANDLE);
      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;
    }

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

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

// =================================================
// Выбор шрифта с фиксированной шириной символов
// =================================================

void SetCourierFont(HPS hps)
{
  FATTRS fat;

  // Заполняем структуру описанием нужного
  // нам шрифта
  fat.usRecordLength = sizeof(FATTRS);
  strcpy(fat.szFacename ,"Courier");
  fat.fsSelection = 0;
  fat.lMatch = 0L;
  fat.idRegistry = 0;
  fat.usCodePage = 850;
  fat.lMaxBaselineExt = 12L;
  fat.lAveCharWidth = 12L;
  fat.fsType = 0;
  fat.fsFontUse = FATTR_FONTUSE_NOMIX;

  // Создаем логический шрифт, имеющий идентификатор 1L
  GpiCreateLogFont(hps, NULL, 1L, &fat);

  // Выбираем созданный шрифт в пространство отображения
  GpiSetCharSet(hps, 1L);
}

// =================================================
// Установка шрифта, выбранного в пространство
// отображения по умолчанию
// =================================================
void ResetFont(HPS hps)
{
  GpiSetCharSet(hps, LCID_DEFAULT);
  GpiDeleteSetId(hps, 1L);
}


