// ----------------------------------------
// Приложение REGIONS
// Демонстрация использования области ограничения
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <mem.h>

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

// Имя класса окна
char const szClassName[]   = "RegionsClass";

// Заголовок окна
char const szWindowTitle[] = "Regions";

// Размеры внутренней области окна
short cxClient, cyClient;

// Размеры символов 
int cxChar, cyChar;

// Текст для вывода в окне приложения
char const szText[] =
 "В интерфейсе GDI есть средства, позволяющие приложениям"
 " создавать области достаточно сложной формы из"
 " прямоугольных, многоугольных и эллиптических областей."
 " Такие области можно закрашивать или использовать"
 " в качестве маски при выводе графического изображения. "
 "В последнем случае область называется областью"
 " ограничения. Она должна быть выбрана в контекст отображения.";

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, 
	HINSTANCE hPrevInstance,
	LPSTR     lpszCmdLine, 
	int       nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0, 0, hInstance, NULL);      
                       
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна
  // Записываем во все поля структуры нулевые значения
  memset(&wc, 0, sizeof(wc));

  wc.lpszMenuName  = NULL;
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  static TEXTMETRIC tm;
  static HRGN hrgn1, hrgn2, hrgn3, hrgnTemp, hrgnClip;
  HBRUSH hbrush;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Определяем метрику шрифта
      hdc = GetDC(hwnd);
      GetTextMetrics(hdc, &tm);
      ReleaseDC(hwnd, hdc);

      // Высота и средняя ширина букв
      cyChar = tm.tmHeight + tm.tmExternalLeading;
      cxChar = tm.tmAveCharWidth;

      // Область ограничения не задана
      hrgnClip = NULL;

      return 0;
    }

    // При изменении размеров окна сохраняем
    // новые значения для ширины и высоты,
    // а также определяем область ограничения
    case WM_SIZE:
    {
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);

      // Если область огранчения бвла определена раньше,
      // удаляем ее
      if(hrgnClip)
        DeleteRgn(hrgnClip);

      // Формируем область ограничения
      hrgnClip = CreateEllipticRgn(0, 0, cxClient, cyClient);

      // Временная область ограничения
      hrgnTemp = CreateEllipticRgn(0, 0, cxClient, cyClient);

      // Первая эллиптическая область
      hrgn1 = CreateEllipticRgn(0, 0, cxClient, cyClient);

      // Вторая эллиптическая область
      hrgn2 = CreateEllipticRgn(cxClient/3, cyClient/3,
         2*(cxClient/3), 2*(cyClient/3));

      // Прямоугольная область
      hrgn3 = CreateRectRgn(cxClient/20, cyClient/20,
         19*(cxClient/20), 19*(cyClient/20));

      // Комбинируем области
      UnionRgn(hrgnTemp, hrgn1, hrgn3);
      SubtractRgn(hrgnClip, hrgnTemp, hrgn2);

      // Удаляем временные области
      DeleteRgn(hrgn1);
      DeleteRgn(hrgn2);
      DeleteRgn(hrgn3);
      DeleteRgn(hrgnTemp);
      return 0;
    }

    // Рисование в окне
    case WM_PAINT:
    {
      RECT rc;

      // Получаем контекст отображения для
      // рисования во внутренней области окна 
      hdc = BeginPaint(hwnd, &ps);

      // Выбираем встроенную кисть зеленого цвета
      hbrush = CreateSolidBrush(RGB(0, 0xff, 0));

      // Обводим границы области
      FrameRgn(hdc, hrgnClip, hbrush, 2, 5);

      // Выбираем область ограничения в контекст
      // отображения
      SelectClipRgn(hdc, hrgnClip);

      // Определяем координаты прямоугольной
      // области для вывода текста
      rc.left = cxChar;
      rc.top  = 0;
      rc.right  = cxClient - cxChar;
      rc.bottom = cyClient;

      // Вывод текста
      DrawText(hdc, szText, lstrlen(szText), &rc,
        DT_LEFT | DT_WORDBREAK);

      // Освобождаем контекст отображения
      EndPaint(hwnd, &ps);
      return 0;
    }

    case WM_DESTROY:
    {
      // удаляем область ограничения
      DeleteRgn(hrgnClip);

      PostQuitMessage(0);
      return 0;
    }

    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

