#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#include "afxres.h"
#include "smart.h"

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------
HINSTANCE hInst;
char szAppName[] = "Smart";
char szAppTitle[] = "Smart Application";

HWND hwndTb;        // идентификатор Toolbar
HWND hwndSb;        // идентификатор Statusbar
int ptWidth[3];     // таблица ширин для Statusbar
HBITMAP hSbLogoBmp; // изображение для Statusbar

// Идентификаторы строк описания временных меню
UINT nIdPopup[] =
{
  IDS_FILEMENU,
  IDS_EDITMENU,
  IDS_HELPMENU
};

// Описание кнопок Toolbar
TBBUTTON tbButtons[] = 
{
  { 0, ID_FILE_NEW,  TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 1, ID_FILE_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 2, ID_FILE_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
  { 3, ID_EDIT_CUT,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 4, ID_EDIT_COPY,  TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 5, ID_EDIT_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
  { 6, ID_FILE_PRINT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
  { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
  { 7, ID_HELP_ABOUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}
};

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    if(IsIconic(hWnd))
	  ShowWindow(hWnd, SW_RESTORE);
	SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICONSM), IMAGE_ICON, 16, 16, 0);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
  wc.lpszClassName = szAppName;
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Инициализируем библиотеку стандартных органов управления
  InitCommonControls();

  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
   	 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно и запускаем цикл обработки сообщений
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_CREATE,     WndProc_OnCreate);
    HANDLE_MSG(hWnd, WM_DESTROY,    WndProc_OnDestroy);
    HANDLE_MSG(hWnd, WM_COMMAND,    WndProc_OnCommand);
    HANDLE_MSG(hWnd, WM_NOTIFY,     WndProc_OnNotify);
    HANDLE_MSG(hWnd, WM_SIZE,       WndProc_OnSize);
    HANDLE_MSG(hWnd, WM_DRAWITEM,   WndProc_OnDrawItem);
    HANDLE_MSG(hWnd, WM_MENUSELECT, WndProc_OnMenuSelect);

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

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  // Создаем Toolbar
  hwndTb = CreateToolbarEx(hWnd,
    WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS |
      CCS_ADJUSTABLE,
    IDT_TOOLBAR,            // идентификатор органа Toolbar
    8,                      // количество пиктограмм
    hInst,                  // идентификатор приложения
    IDB_TBBITMAP,           // идентификатор битового изображения
                            //   кнопок
    (LPCTBBUTTON)&tbButtons,// адрес описания кнопок
    11,                     // количество кнопок
    16,16,                  // ширина и высота кнопок
    16,16,                  // ширина и высота пиктограмм
    sizeof(TBBUTTON));      // размер структуры в байтах 

  if(hwndTb == NULL)
    return FALSE;

  // Создаем Statusbar
  hwndSb = CreateWindowEx( 
    0L,                     // расширенный стиль окна
    STATUSCLASSNAME,        // класс окна для Statusbar
    "",                     // заголовок окна отсутствует
    WS_CHILD | WS_BORDER |  // стиль окна
    WS_VISIBLE | SBARS_SIZEGRIP,
    0, 0, 0, 0,             // координаты, ширина, высота
    hWnd,                   // идентификатор родительского окна
    (HMENU)IDS_STATUSBAR,   // идентификатор Statusbar
    hInst,                  // идентификатор приложения
    NULL );                 // доп. данные для окна

  if(hwndSb == NULL)
    return FALSE;
  
  // Делим Statusbar на 3 области
  SendMessage(hwndSb, SB_SETPARTS, 3, (LPARAM)ptWidth);

  // Инициализируем области Statusbar
  SendMessage(hwndSb, SB_SETTEXT, 0, (LPARAM)"");
  SendMessage(hwndSb, SB_SETTEXT, 1 | SBT_NOBORDERS,
    (LPARAM)"");
  
  // Загружаем изображение, которое будет нарисовано
  // в третьей части Statusbar
  hSbLogoBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SBLOGO));
  
  if(hSbLogoBmp== NULL)
    return FALSE;

  // Рисуем это изображение
  SendMessage(hwndSb, SB_SETTEXT, 2 | SBT_OWNERDRAW,
   (LPARAM)hSbLogoBmp);

  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  PostQuitMessage(0);
  return FORWARD_WM_DESTROY(hWnd, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
  	case ID_FILE_EXIT:
	  PostQuitMessage(0);
	  break;
	  
  	case ID_FILE_NEW:
	case ID_FILE_OPEN:
	case ID_FILE_SAVE:
	case ID_FILE_SAVEAS:
	case ID_FILE_PRINT:
	case ID_EDIT_CUT:
	case ID_EDIT_COPY:
	case ID_EDIT_PASTE:
	case ID_HELP_ABOUT:

  	default:
      MessageBox(NULL, "Command stub", 
        "Smart Application", MB_OK);
  }
  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify,
   DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnNotify
// -----------------------------------------------------
LRESULT WndProc_OnNotify(HWND hWnd, int idFrom, NMHDR* pnmhdr)
{
  LPTOOLTIPTEXT lpToolTipText;
  LPTBNOTIFY lptbn;
  int nItem;
  static CHAR szBuf[128];

  switch(pnmhdr->code)
  {
    // Если получили сообщение от ToolTips, загружаем из ресурсов
    // соответствующую текстовую строку
    case TTN_NEEDTEXT:
      lpToolTipText = (LPTOOLTIPTEXT)pnmhdr;
	  LoadString(hInst, lpToolTipText->hdr.idFrom,
	    szBuf, sizeof(szBuf));
	  lpToolTipText->lpszText = szBuf;
      break;

    // Возвращаем окну Toolbar характеристики кнопки,
	// с номером, заданным в lptbn->iItem
    case TBN_GETBUTTONINFO:
      lptbn = (LPTBNOTIFY)pnmhdr; 
	  nItem = lptbn->iItem;
	  lptbn->tbButton.iBitmap   = tbButtons[nItem].iBitmap;
	  lptbn->tbButton.idCommand = tbButtons[nItem].idCommand;
	  lptbn->tbButton.fsState   = tbButtons[nItem].fsState;
	  lptbn->tbButton.fsStyle   = tbButtons[nItem].fsStyle;
	  lptbn->tbButton.dwData    = tbButtons[nItem].dwData;
	  lptbn->tbButton.iString   = tbButtons[nItem].iString;

      // Если запрашиваются характеристики несуществующей
	  // кнопки, возвращаем FALSE
      return ((nItem < sizeof(tbButtons)/sizeof(tbButtons[0]))?
        TRUE : FALSE);
      break;
  
    // Разрешаем удаление любой кнопки, кроме самой первой
    case TBN_QUERYDELETE:
      lptbn = (LPTBNOTIFY)pnmhdr; 
	  nItem = lptbn->iItem;
      return (nItem == 0)? FALSE : TRUE;
      break;
    
    // Разрешаем вставку любой кнопки, кроме самой первой
    case TBN_QUERYINSERT:
      lptbn = (LPTBNOTIFY)pnmhdr; 
	  nItem = lptbn->iItem;
      return (nItem == 0)? FALSE : TRUE;
      break;
    
    // В ответ на завершение операции перемещения 
	// перерисовываем Toolbar
    case TBN_TOOLBARCHANGE:
      SendMessage(hwndTb, TB_AUTOSIZE, 0L, 0L);
      return TRUE;
	  break;
    
    default:
      break;
  }
  return FALSE;
}

// -----------------------------------------------------
// Функция WndProc_OnSize       
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
  // Изменяем размеры Toolbar и Statusbar в соответствии с
  // новыми размерами окна
  SendMessage(hwndTb, WM_SIZE, cx, cy);
  SendMessage(hwndSb, WM_SIZE, cx, cy);

  // Рассчитываем размеры областей Statusbar
  ptWidth[0] = cx/2;
  ptWidth[1] = cx/2 + cx/4;
  ptWidth[2] = -1;
  
  // Устанавливаем новые размеры Statusbar
  SendMessage(hwndSb, SB_SETPARTS, 3, (LPARAM)ptWidth);

  return FORWARD_WM_SIZE(hwnd, state, cx, cy, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnDrawItem      
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDrawItem(HWND hwnd, 
  const DRAWITEMSTRUCT * lpDrawItem)
{
  // Необходимо выполнить перерисовку области Statusbar,
  // которая была определена как SBT_OWNERDRAW
  if(lpDrawItem->CtlID == IDS_STATUSBAR)
  {
    LPDRAWITEMSTRUCT lpDis;
    HDC hdcMem;
    HBITMAP hbmOld;
    BITMAP bm;

    // Рисуем битовое изображение внутри области
    lpDis = (LPDRAWITEMSTRUCT)lpDrawItem;
    hdcMem = CreateCompatibleDC(lpDis->hDC);

    hbmOld = SelectObject(hdcMem, hSbLogoBmp);
    GetObject(hSbLogoBmp, sizeof(bm), &bm);

    BitBlt(lpDis->hDC, 
      lpDis->rcItem.left, lpDis->rcItem.top,
      bm.bmWidth, bm.bmHeight, 
      hdcMem, 0, 0, SRCCOPY);

    SelectObject(hdcMem, hbmOld);
    DeleteDC(hdcMem);
  }

  return FORWARD_WM_DRAWITEM(hwnd, lpDrawItem, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnMenuSelect
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, 
  HMENU hmenuPopup, UINT flags)
{
  static char szBuf[128];
  UINT nStrID = 0;
  szBuf[0] = 0;

  // Пользователь закрыл меню
  if(flags == 0xffffffff && hmenu == NULL)
    nStrID = IDS_DESCRIPTION;

  // Пользователь выделил в меню строку разделителя
  else if(flags & MFT_SEPARATOR)
    nStrID = 0;

  // Выбрано временное меню
  else if(flags & MF_POPUP)
  {
    // Выбрано системное меню
    if(flags & MF_SYSMENU)
      nStrID = IDS_SYSMENU;
    
    // Вычмсляем идентификатор строки, описывающей
    // временное меню
    else
      nStrID = ((item < sizeof(nIdPopup)/sizeof(nIdPopup[0]))?
        nIdPopup[item] : 0);
  }
  
  // Используем идентификатор строки, соответствующий
  // выделенной строке меню
  else nStrID = item;

  // Загружаем строку из ресурсов приложения
  if(nStrID != 0)
    LoadString(hInst, nStrID, szBuf, sizeof(szBuf));

  // Отображаем строку в первой области Toolbar
  SendMessage(hwndSb, SB_SETTEXT, 0, (LPARAM)szBuf);
  
  return FORWARD_WM_MENUSELECT(hwnd, hmenu, item,
    hmenuPopup, flags, DefWindowProc);
}
