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

#define STRICT
#include <windows.h>
#include <stdio.h>
#include <string.h>

void Print(HDC, int, char *);

static int cxChar, cyChar;
static int cxCurrentPosition;
static int cyCurrentPosition;
static int nScrollPos;

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static WORD cxClient, cyClient;

  HDC hdc;              // индекс контекста устройства
  PAINTSTRUCT ps;       // структура для рисования
  static TEXTMETRIC tm; // структура для записи метрик
                        // шрифта

  switch (msg)
  {
    case WM_CREATE:
    {
      // Получаем контекст отображения,
      // необходимый для определения метрик шрифта
      hdc = GetDC(hwnd);

      // Заполняем структуру информацией
      // о метрике шрифта, выбранного в
      // контекст отображения
      GetTextMetrics(hdc, &tm);

      // Запоминаем значение ширины для
      // самого широкого символа
      cxChar = tm.tmMaxCharWidth;

      // Запоминаем значение высоты букв с
      // учетом межстрочного интервала
      cyChar = tm.tmHeight + tm.tmExternalLeading;

      // Инициализируем текущую позицию
      // вывода текста
      cxCurrentPosition = cxChar;
      cyCurrentPosition = 0;

      // Освобождаем контекст
      ReleaseDC(hwnd, hdc);

      // Начальное значение позиции
      nScrollPos = 0;

      // Задаем диапазон изменения значений
      SetScrollRange(hwnd, SB_VERT, 0, 20, FALSE);

      // Устанавливаем ползунок в начальную позицию
      SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);

      return 0;
    }

    // Определяем размеры внутренней области окна
    case WM_SIZE:
    {
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);
      return 0;
    }

    // Сообщение от вертикальной полосы просмотра
    case WM_VSCROLL:
    {
      switch(wParam)
      {
	case SB_TOP:
	{
	  nScrollPos = 0;
          break;
        }
	case SB_BOTTOM:
	{
	  nScrollPos = 20;
          break;
        }
	case SB_LINEUP:
	{
	  nScrollPos -= 1;
          break;
        }
	case SB_LINEDOWN:
	{
	  nScrollPos += 1;
          break;
        }
	case SB_PAGEUP:
	{
	  nScrollPos -= cyClient / cyChar;
          break;
        }
	case SB_PAGEDOWN:
	{
	  nScrollPos += cyClient / cyChar;
          break;
        }
	case SB_THUMBPOSITION:
	{
	  nScrollPos = LOWORD(lParam);
          break;
	}
	// Блокируем для того чтобы избежать
	// мерцания содержимого окна при
	// перемещении ползунка
	case SB_THUMBTRACK:
	{
	  return 0;
	}
	default:
          break;
      }

      // Ограничиваем диапазон изменения значений
      if(nScrollPos > 20) nScrollPos = 20;
      if(nScrollPos < 0) nScrollPos = 0;

      // Устанавливаем ползунок в новое положение
      SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);

      // Обновляем окно
      InvalidateRect(hwnd, NULL, TRUE);

      return 0;
    }

    case WM_PAINT:
    {
      // Инициализируем текущую позицию
      // вывода текста
      cxCurrentPosition = cxChar;
      cyCurrentPosition = 0;

      hdc = BeginPaint(hwnd, &ps);

      // Выводим параметры шрифта, полученные во
      // время создания окна при обработке
      // сообщения WM_CREATE
      Print(hdc, tm.tmHeight,          "tmHeight");
      Print(hdc, tm.tmAscent,          "tmAscent");
      Print(hdc, tm.tmDescent,         "tmDescent");
      Print(hdc, tm.tmInternalLeading, "tmInternalLeading");
      Print(hdc, tm.tmExternalLeading, "tmExternalLeading");
      Print(hdc, tm.tmAveCharWidth,    "tmAveCharWidth");
      Print(hdc, tm.tmMaxCharWidth,    "tmMaxCharWidth");
      Print(hdc, tm.tmWeight,          "tmWeight");
      Print(hdc, tm.tmItalic,          "tmItalic");
      Print(hdc, tm.tmUnderlined,      "tmUnderlined");
      Print(hdc, tm.tmStruckOut,       "tmStruckOut");
      Print(hdc, tm.tmFirstChar,       "tmFirstChar");
      Print(hdc, tm.tmLastChar,        "tmLastChar");
      Print(hdc, tm.tmDefaultChar,     "tmDefaultChar");
      Print(hdc, tm.tmBreakChar,       "tmBreakChar");
      Print(hdc, tm.tmPitchAndFamily,  "tmPitchAndFamily");
      Print(hdc, tm.tmCharSet,         "tmCharSet");
      Print(hdc, tm.tmOverhang,        "tmOverhang");
      Print(hdc, tm.tmDigitizedAspectX,"tmDigitizedAspectX");
      Print(hdc, tm.tmDigitizedAspectY,"tmDigitizedAspectY");

      EndPaint(hwnd, &ps);
      return 0;
    }

    // Обеспечиваем управление полосой просмотра
    // при помощи клавиатуры
    case WM_KEYDOWN:
    {
      // В зависимости от кода клавиши функция окна
      // посылает сама себе сообщения, которые
      // обычно генерируются полосой просмотра
      switch (wParam)
      {
	case VK_HOME:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0L);
          break;
        }
	case VK_END:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
          break;
        }
	case VK_UP:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0L);
          break;
        }
	case VK_DOWN:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0L);
          break;
        }
	case VK_PRIOR:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0L);
          break;
        }
	case VK_NEXT:
	{
	  SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L);
          break;
        }
      }
      return 0;
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// ==========================================
// Функция для вывода параметров шрифта
// в окно
// ==========================================

void Print(HDC hdc, int tmValue, char *str)
{
  char buf[80];
  int i, y;

  // Вычисляем начальную позицию для вывода
  y = cyCurrentPosition + cyChar * (1 - nScrollPos);

  // Подготавливаем в рабочем буфере
  // и выводим в окно начиная с текущей
  // позиции название параметра
  sprintf(buf, "%s", str);
  i = strlen(str);

  TextOut(hdc,
    cxCurrentPosition, y, buf, i);

  // Подготавливаем в рабочем буфере
  // и выводим в текущей строке окна
  // со смещением значение параметра
  sprintf(buf, "= %d", tmValue);
  i = strlen(buf);

  TextOut(hdc,
    cxCurrentPosition + 12 * cxChar, y, buf, i);

  // Увеличиваем текущую позицию по
  // вертикали на высоту символа
  cyCurrentPosition += cyChar;
}
