// ----------------------------------------
// Приложение LINER
// Демонстрация использования функций
// рисования графических изображений
// ----------------------------------------

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

#include "liner.hpp"

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawLines(HDC);
void DrawPolyline(HDC);
void DrawArc(HDC);
void DrawRectangles(HDC);
void DrawPolygon(HDC);
void DrawEllipse(HDC);
void DrawCircle(HDC);
void DrawPie(HDC);
void DrawChord(HDC);

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

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

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

// Код выбранной строки меню "Draw"
int nFigures = 0;

// Режим фона
int nBkMode = OPAQUE;

// Код растровой операции
int nROP2 = R2_COPYPEN;

// =====================================
// Функция 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  = "APP_MENU";

  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(LTGRAY_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;

  switch (msg)
  {
    // При изменении размеров окна сохраняем
    // новые значения для ширины и высоты
    case WM_SIZE:
    {
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);
      return 0;
    }

    // Рисование в окне
    case WM_PAINT:
    {
      HBRUSH hbrush, hbrushOldBrush;
      int nCapHeight, nFrameHeight;

      // Рисуем в области заголовка окна

      // Получаем контекст отображения для
      // всего окна
      hdc = GetWindowDC(hwnd);

      // Определяем высоту заголовка окна
      nCapHeight = GetSystemMetrics(SM_CYCAPTION);

      // Определяем толщину рамки окна
      nFrameHeight = GetSystemMetrics(SM_CYFRAME);

      // Создаем кисть зеленого цвета
      hbrush = CreateSolidBrush(RGB(0,0xff,0));

      // Выбираем кисть в контекст отображения, сохраняя
      // идентификатор старой кисти
      hbrushOldBrush = SelectBrush(hdc, hbrush);

      // Рисуем зеленый прямоугольник в левой  части
      // заголовка окна
      Rectangle(hdc,
        2*nCapHeight, nFrameHeight,
        4*nCapHeight, nCapHeight);

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

      // Вписываем в прямоугольник эллипс
      // красного цвета
      Ellipse(hdc,
        2*nCapHeight, nFrameHeight,
        4*nCapHeight, nCapHeight);

      // Выбираем старую кисть
      SelectBrush(hdc, hbrushOldBrush);

      // Освобождаем контекст отображения,
      // позволяющий рисовать во всем окне
      ReleaseDC(hwnd, hdc);

      // Рисуем во внутренней области окна

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

      // Устанавливаем метрическую систему
      // координат с началом координат в
      // левом нижнем углу внутренней области
      // окна
      SetMapMode(hdc, MM_LOMETRIC);
      SetViewportOrg(hdc, 0, cyClient);

      // Устанавливаем режим отображения и
      // растровую операцию
      SetBkMode(hdc, nBkMode);
      SetROP2(hdc, nROP2);

      // В зависимости от содержимого переменной
      // nFigures вызываем одну из функций рисования
      if(nFigures == CM_LINES)
      {
        DrawLines(hdc);      // прямые линии
      }
      else if(nFigures == CM_ARC)
      {
        DrawArc(hdc);        // дуга окружности
      }
      else if(nFigures == CM_RECT)
      {
        DrawRectangles(hdc); // прямоугольники
      }
      else if(nFigures == CM_POLYGON)
      {
        DrawPolygon(hdc);    // многоугольники
      }
      else if(nFigures == CM_ELLIPSE)
      {
        DrawEllipse(hdc);    // эллипс
      }
      else if(nFigures == CM_CIRCLE)
      {
        DrawCircle(hdc);     // окружность
      }
      else if(nFigures == CM_PIE)
      {
        DrawPie(hdc);        // сектор эллипса
      }
      else if(nFigures == CM_CHORD)
      {
        DrawChord(hdc);      // сегмент эллипса
      }
      else if(nFigures == CM_POLYLINE)
      {
        DrawPolyline(hdc);   // ломаная линия
      }

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

    // Обработка сообщений от меню
    case WM_COMMAND:
    {
      switch (wParam)
      {
        case CM_HELPABOUT:
        {
          MessageBox(hwnd,
            "Liner, v.1.0\n"
            "Drawing Graphics Demo\n"
            "(C) Frolov A.V., 1994",
	    "About Liner", MB_OK | MB_ICONINFORMATION);
          return 0;
        }

        // Режим непрозрачного фона
        case CM_OPAQUE:
        {
          // Записываем код режима
          nBkMode = OPAQUE;

          // Перерисовываем окно приложения
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // Режим прозрачного фона
        case CM_TRANSPARENT:
        {
          nBkMode = TRANSPARENT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // Выбор растровой операции
        case CM_R2_BLACK:
        {
          // Записываем код растровой операции
          nROP2 = R2_BLACK;

          // Перерисовываем окно приложения
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOTMERGEPEN:
        {
          nROP2 = R2_NOTMERGEPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MASKNOTPEN:
        {
          nROP2 = R2_MASKNOTPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOTCOPYPEN:
        {
          nROP2 = R2_NOTCOPYPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MASKPENNOT:
        {
          nROP2 = R2_MASKPENNOT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOT:
        {
          nROP2 = R2_NOT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_XORPEN:
        {
          nROP2 = R2_XORPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOTMASKPEN:
        {
          nROP2 = R2_NOTMASKPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MASKPEN:
        {
          nROP2 = R2_MASKPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOTXORPEN:
        {
          nROP2 = R2_NOTXORPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_NOP:
        {
          nROP2 = R2_NOP;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MERGENOTPEN:
        {
          nROP2 = R2_MERGENOTPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_COPYPEN:
        {
          nROP2 = R2_COPYPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MERGEPENNOT:
        {
          nROP2 = R2_MERGEPENNOT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_MERGEPEN:
        {
          nROP2 = R2_MERGEPEN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_R2_WHITE:
        {
          nROP2 = R2_WHITE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // Выбор из меню "Draw"
        case CM_LINES:
        {
          nFigures = CM_LINES;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_POLYLINE:
        {
          nFigures = CM_POLYLINE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_ARC:
        {
          nFigures = CM_ARC;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_RECT:
        {
          nFigures = CM_RECT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_POLYGON:
        {
          nFigures = CM_POLYGON;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_ELLIPSE:
        {
          nFigures = CM_ELLIPSE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_CIRCLE:
        {
          nFigures = CM_CIRCLE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_PIE:
        {
          nFigures = CM_PIE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_CHORD:
        {
          nFigures = CM_CHORD;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // Завершаем работу приложения
        case CM_FILEEXIT:
        {
          DestroyWindow(hwnd);
          return 0;
        }

        default:
          return 0;
      }
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }

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

