// ----------------------------------------------
// Использование графических изображений в меню 
// ----------------------------------------------

#define STRICT
#include <windows.h>
#include <mem.h>
#include "gmenu.hpp"

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

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

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

// Идентификатор меню верхнего уровня
HMENU hmenu;

// Идентификаторы временных меню
HMENU hmenuFile;      // "File"
HMENU hmenuLineStyle; // "Edit"
HMENU hmenuHelp;      // "Help"

// Идентификаторы графических изображений для строк меню
HBITMAP hbmpLine1;
HBITMAP hbmpLine2;
HBITMAP hbmpLine3;
HBITMAP hbmpLine4;
HBITMAP hbmpLineStyle;
HBITMAP hbmpChecked;
HBITMAP hbmpUnchecked;

// Идентификатор текущей копии приложения
HINSTANCE hInst;

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

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

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

  // Сохраняем идентификатор текущей копии приложения
  hInst = hInstance;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  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         = 0;
  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)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szClassName;

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

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

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
    case WM_CREATE:
    {
      // Загружаем изображения строк меню
      hbmpLine1     = LoadBitmap(hInst, "LINE1");
      hbmpLine2     = LoadBitmap(hInst, "LINE2");
      hbmpLine3     = LoadBitmap(hInst, "LINE3");
      hbmpLine4     = LoadBitmap(hInst, "LINE4");
      hbmpLineStyle = LoadBitmap(hInst, "LINESTYLE");
      hbmpChecked   = LoadBitmap(hInst, "CHECKED");
      hbmpUnchecked = LoadBitmap(hInst, "UNCHECKED");

      // Создаем пустое меню верхнего уровня
      hmenu = CreateMenu();

      // Подключаем меню к главному окну приложения
      SetMenu(hwnd, hmenu);

      // Создаем временные меню
      hmenuFile = CreatePopupMenu();
      hmenuHelp = CreatePopupMenu();
      hmenuLineStyle = CreatePopupMenu();

      // Добавляем строки к меню "File"
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILENEW,    "&New");
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILEOPEN,   "&Open");
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILECLOSE,  "&Close");
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILESAVE,   "&Save");
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILESAVEAS, "Save &as...");
      AppendMenu(hmenuFile, MF_SEPARATOR, 0, NULL);
      AppendMenu(hmenuFile, MF_DISABLED | MF_STRING,
         CM_FILEDEMO, "&Demo Version");
      AppendMenu(hmenuFile, MF_SEPARATOR, 0, NULL);
      AppendMenu(hmenuFile, MF_ENABLED | MF_STRING,
         CM_FILEEXIT, "E&xit");

      // Для строки "Demo Version" меню "File" определяем
      // изображения, которые будут использоваться для
      // вывода строки в отмеченном и неотмеченном состоянии
      SetMenuItemBitmaps(hmenuFile, CM_FILEDEMO, MF_BYCOMMAND,
        hbmpUnchecked, hbmpChecked);

      // Отмечаем строку "Demo Version"
      CheckMenuItem(hmenuFile, CM_FILEDEMO,
         MF_BYCOMMAND | MF_CHECKED);

      // Добавляем строки к меню "Line Style".
      // Вместо текстовых строк используем графические
      // изображения bitmap 
      AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP,
         CM_LINE1, (LPCSTR)(DWORD)hbmpLine1);
      AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP,
         CM_LINE2, (LPCSTR)(DWORD)hbmpLine2);
      AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP,
         CM_LINE3, (LPCSTR)(DWORD)hbmpLine3);
      AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP,
         CM_LINE4, (LPCSTR)(DWORD)hbmpLine4);

      // Добавляем строки к меню "Help"
      AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING,
         CM_HELPINDEX, "&Index\tF1");
      AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING,
         CM_HELPKEYBOARD, "&Keyboard");
      AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING,
         CM_HELPCOMMANDS, "&Commands");
      AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING,
         CM_HELPPROCEDURES, "&Procedures");
      AppendMenu(hmenuHelp, MF_GRAYED | MF_STRING,
         CM_HELPUSING_HELP, "&Using help");
      AppendMenu(hmenuHelp, MF_SEPARATOR, 0, NULL);
      AppendMenu(hmenuHelp, MF_ENABLED | MF_STRING,
         CM_HELPABOUT, "&About...");

      // Добалвяем временные меню к меню верхнего уровня
      AppendMenu(hmenu, MF_ENABLED | MF_POPUP,
         (UINT)hmenuFile, "&File");

      // Для временного меню "Line Style" используем
      // изображение bitmap
      AppendMenu(hmenu, MF_ENABLED | MF_POPUP | MF_BITMAP,
         (UINT)hmenuLineStyle, (LPCSTR)(DWORD)hbmpLineStyle);

      AppendMenu(hmenu, MF_ENABLED | MF_POPUP,
         (UINT)hmenuHelp, "&Help");

      // Перерисовываем меню
      DrawMenuBar(hwnd);
      return 0;
    }

    case WM_COMMAND:
    {
      switch (wParam)
      {
        // Сообщения от меню
	case CM_HELPUSING_HELP:
        case CM_HELPPROCEDURES:
        case CM_HELPCOMMANDS:
        case CM_HELPKEYBOARD:
        case CM_HELPINDEX:
        case CM_FILESAVEAS:
        case CM_FILESAVE:
	case CM_FILEOPEN:
	case CM_FILENEW:
	case CM_FILECLOSE:
	{
          // Выводим сообщение об ошибке
	  MessageBox(hwnd, "Функция не реализована",
	          NULL, MB_OK);
          return 0;
	}

        // Выбрали строку "About..." в меню "Help"
	case CM_HELPABOUT:
	{
	  MessageBox(hwnd, "Приложение GMENU\n(C) Фролов А.В., 1994",
		  szWindowTitle, MB_OK | MB_ICONINFORMATION);
          return 0;
	}

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

        default:
          return 0;
      }
    }

    case WM_DESTROY:
    {
      // Уничтожаем созданные ранее меню
      DestroyMenu(hmenuFile);
      DestroyMenu(hmenuHelp);
      DestroyMenu(hmenuLineStyle);
      DestroyMenu(hmenu);

      // Удаляем изображения
      DeleteObject(hbmpLine1);
      DeleteObject(hbmpLine2);
      DeleteObject(hbmpLine3);
      DeleteObject(hbmpLine4);
      DeleteObject(hbmpLineStyle);
      DeleteObject(hbmpChecked);
      DeleteObject(hbmpUnchecked);

      PostQuitMessage(0);
      return 0;
    }

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