Advertisement
Guest User

Untitled

a guest
Dec 11th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.51 KB | None | 0 0
  1. #include <sdkddkver.h>
  2. // select sdk version to determine common controls functionality
  3. #undef WINVER
  4. #define WINVER _WIN32_WINNT_NT4  // that's enough for table control
  5. #undef _WIN32_WINNT
  6. #define _WIN32_WINNT WINVER
  7. #define _WIN32_IE WINVER
  8. #include <windows.h>
  9. #include <commctrl.h>
  10. #include <stdio.h>
  11.  
  12. #define CHESSBOARD_ID 3001
  13.  
  14. #define MAX_STR_LEN 255
  15. #define WHITE_CELL_CLR RGB(255, 206, 158)
  16. #define BLACK_CELL_CLR RGB(209, 139, 71)
  17. #define FIGURES_FONT_CLR RGB(0, 0, 0)
  18. #define BACKGROUND_CLR RGB(100, 50, 30)
  19. #define LETTERS_FONT_CLR RGB(255, 206, 158)
  20. #define CELL_SIZE 80
  21. #define CHESSBOARD_COLS 10
  22. #define CHESSBOARD_ROWS 10
  23. #define CHESSBOARD_1ST_COL 1    // in grid
  24. #define CHESSBOARD_1ST_ROW 1    // in grid
  25. #define CHESSBOARD_LAST_COL 8   // in grid
  26. #define CHESSBOARD_LAST_ROW 8   // in grid
  27. #define CHESSBOARD_LEFT_CAPTIONS 0
  28. #define CHESSBOARD_RIGHT_CAPTIONS (CHESSBOARD_COLS - 1)
  29. #define CHESSBOARD_TOP_CAPTIONS 0
  30. #define CHESSBOARD_BOTTOM_CAPTIONS (CHESSBOARD_ROWS - 1)
  31.  
  32. typedef enum {EMPTY, BLACK_PAWN, WHITE_PAWN, BLACK_KNIGHT, WHITE_KNIGHT,
  33.               BLACK_BISHOP, WHITE_BISHOP, BLACK_ROOK, WHITE_ROOK, BLACK_QUEEN,
  34.               WHITE_QUEEN, BLACK_KING, WHITE_KING} ChessFigures;
  35.  
  36. static LPWSTR CHESS_FIGURES_SMB[] = {L"", L"\u265F", L"\u2659", L"\u265E",
  37.     L"\u2658", L"\u265D", L"\u2657", L"\u265C", L"\u2656", L"\u265B",
  38.     L"\u2655", L"\u265A", L"\u2654"};
  39. static const INT START_POSITION[8][8] = {
  40.     {BLACK_ROOK, BLACK_KNIGHT, BLACK_BISHOP, BLACK_QUEEN, BLACK_KING,
  41.      BLACK_BISHOP, BLACK_KNIGHT, BLACK_ROOK},
  42.     {BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN,
  43.      BLACK_PAWN, BLACK_PAWN},
  44.     {EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY},
  45.     {EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY},
  46.     {EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY},
  47.     {EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY},
  48.     {WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN,
  49.      WHITE_PAWN, WHITE_PAWN},
  50.     {WHITE_ROOK, WHITE_KNIGHT, WHITE_BISHOP, WHITE_QUEEN, WHITE_KING,
  51.      WHITE_BISHOP, WHITE_KNIGHT, WHITE_ROOK}};
  52.  
  53. static HINSTANCE instance = NULL;
  54. static HWND mainWin = NULL;
  55. static HWND chessboard = NULL;
  56. static HFONT figuresFont = 0;
  57. static HFONT lettersFont = 0;
  58. static INT board[8][8] = {{0}};
  59.  
  60. HWND CreateMainWindow(VOID);
  61. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
  62. VOID ResizeWindow(HWND hWnd, INT width, INT height);
  63. SIZE GetWindowSize(HWND hWnd, BOOL internal);
  64. LRESULT ProcessChessboardDraw(LPARAM lParam);
  65. VOID InitFonts(VOID);
  66. VOID ProcessChessboardClick(LPARAM lParam);
  67. LPWSTR PosToChessNotation(INT col, INT row, LPWSTR out);
  68. LPWSTR ColToChessNotation(INT col, LPWSTR out);
  69. LPWSTR RowToChessNotation(INT row, LPWSTR out);
  70. BOOL IsCellInsideBoard(INT col, INT row);
  71. HWND CreateStringGrid(HWND parent, INT id, HFONT font);
  72. VOID StringGridChangeFont(HWND sg, HFONT font);
  73. VOID StringGridAddCol(HWND sg);
  74. VOID StringGridAddRow(HWND sg);
  75. VOID StringGridClear(HWND sg);
  76. VOID StringGridResize(HWND sg, INT cols, INT rows);
  77. SIZE StringGridAutoSize(HWND sg, INT rows);
  78. INT StringGridColCount(HWND sg);
  79. INT StringGridSetItem(HWND sg, INT col, INT row, LPWSTR text);
  80. VOID AutoSizeAll(VOID);
  81. SIZE AutoSizeChessboard(VOID);
  82. VOID AutoSizeWindow(HWND wnd, SIZE client);
  83. HWND InitChessBoard(HWND wnd);
  84. VOID UpdateChessBoard(VOID);
  85. VOID ResetBoard(VOID);
  86. VOID UpdateChessBoardCaptions(VOID);
  87.  
  88. INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  89.         LPSTR lpCmdLine, INT nCmdShow) {
  90.     instance = hInstance;
  91.     INITCOMMONCONTROLSEX controls = {sizeof(controls), ICC_LISTVIEW_CLASSES};
  92.     InitCommonControlsEx(&controls);
  93.     mainWin = CreateMainWindow();
  94.     MSG msg;
  95.     while (GetMessage(&msg, NULL, 0, 0)) {
  96.         TranslateMessage(&msg);
  97.         DispatchMessage(&msg);
  98.     }
  99.     return (INT)msg.wParam;
  100. }
  101. HWND CreateMainWindow(VOID) {
  102.     HWND result = NULL;
  103.     WNDCLASSEX wcx = {0};
  104.     wcx.cbSize = sizeof(wcx);
  105.     wcx.style = CS_HREDRAW | CS_VREDRAW;
  106.     wcx.lpfnWndProc = MainWndProc;
  107.     wcx.cbClsExtra = 0;
  108.     wcx.cbWndExtra = 0;
  109.     wcx.hInstance = instance;
  110.     wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  111.     wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
  112.     wcx.hbrBackground = GetStockObject(WHITE_BRUSH);
  113.     wcx.lpszMenuName = "MainMenu";
  114.     wcx.lpszClassName = "ChessClass";
  115.     wcx.hIconSm = LoadImage(NULL, MAKEINTRESOURCE(5), IMAGE_ICON,
  116.             GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  117.             LR_DEFAULTCOLOR);
  118.     if (!RegisterClassEx(&wcx) &&
  119.             (GetLastError() != ERROR_CLASS_ALREADY_EXISTS)) {
  120.         MessageBox(NULL, "Can't register window class", "Error", MB_OK);
  121.         return result;
  122.     }
  123.     result = CreateWindow("ChessClass", "Chess",
  124.         WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
  125.         CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, (HMENU)NULL, instance, NULL);
  126.     if (!result) {
  127.         MessageBox(NULL, "Can't create window", "Error", MB_OK);
  128.         return result;
  129.     }
  130.     return result;
  131. }
  132. LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
  133.         LPARAM lParam) {
  134.     switch (uMsg) {
  135.         case WM_CREATE:
  136.             mainWin = hWnd;
  137.             chessboard = InitChessBoard(hWnd);
  138.             ResetBoard();
  139.             UpdateChessBoard();
  140.             AutoSizeAll();
  141.             break;
  142.         case WM_CLOSE:
  143.             DestroyWindow(hWnd);
  144.             break;
  145.         case WM_DESTROY:
  146.             if (hWnd == mainWin) {
  147.                 PostQuitMessage(0);
  148.             }
  149.             break;
  150.         case WM_NOTIFY:
  151.             switch (LOWORD(wParam)) {
  152.                 case CHESSBOARD_ID:
  153.                     switch (((LPNMHDR)lParam)->code) {
  154.                         case NM_CUSTOMDRAW:
  155.                             return ProcessChessboardDraw(lParam);
  156.                             break;
  157.                         case NM_CLICK:
  158.                             ProcessChessboardClick(lParam);
  159.                             break;
  160.                     }
  161.                     break;
  162.             }
  163.             break;
  164.         default:
  165.             return DefWindowProc(hWnd, uMsg, wParam, lParam);
  166.     }
  167.     return 0;
  168. }
  169. VOID ResizeWindow(HWND hWnd, INT width, INT height) {
  170.     SetWindowPos(hWnd, 0, 0, 0, width, height,
  171.                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  172. }
  173. SIZE GetWindowSize(HWND hWnd, BOOL internal) {
  174.     RECT rect = {0};
  175.     if (internal) {
  176.         GetClientRect(hWnd, &rect);
  177.     } else {
  178.         GetWindowRect(hWnd, &rect);
  179.     }
  180.     return (SIZE){rect.right - rect.left, rect.bottom - rect.top};
  181. }
  182. LRESULT ProcessChessboardDraw(LPARAM lParam) {
  183.     LRESULT result = CDRF_DODEFAULT;
  184.     LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
  185.     lplvcd->nmcd.uItemState &= ~(CDIS_FOCUS | CDIS_SELECTED); // hide selection
  186.     INT col = lplvcd->iSubItem;
  187.     INT row = lplvcd->nmcd.dwItemSpec;
  188.     switch (lplvcd->nmcd.dwDrawStage) {
  189.         case CDDS_PREPAINT :  // before the paint cycle begins
  190.             // request notifications for individual listview items
  191.             result = CDRF_NOTIFYITEMDRAW;
  192.             break;
  193.         case CDDS_ITEMPREPAINT:  // before an item is drawn
  194.             result = CDRF_NOTIFYSUBITEMDRAW;
  195.             break;
  196.         case CDDS_SUBITEM | CDDS_ITEMPREPAINT:  // before a subitem is drawn
  197.             if (IsCellInsideBoard(col, row)) {  // set board colors
  198.                 SelectObject(lplvcd->nmcd.hdc, figuresFont);
  199.                 lplvcd->clrText = FIGURES_FONT_CLR;
  200.                 lplvcd->clrTextBk = ((col + row) % 2) ?
  201.                                     BLACK_CELL_CLR : WHITE_CELL_CLR;
  202.             } else {  // set background colors
  203.                 SelectObject(lplvcd->nmcd.hdc, lettersFont);
  204.                 lplvcd->clrTextBk = BACKGROUND_CLR;
  205.                 lplvcd->clrText = LETTERS_FONT_CLR;
  206.             }
  207.             result = CDRF_NEWFONT;
  208.             break;
  209.     }
  210.     return result;
  211. }
  212. VOID InitFonts(VOID) {
  213.     figuresFont = CreateFont(CELL_SIZE, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
  214.         FALSE,  DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  215.         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "");
  216.     lettersFont = CreateFont(CELL_SIZE, 0, 0, 0, FW_THIN, TRUE, FALSE,
  217.         FALSE,  DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  218.         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
  219.         "Courier New");
  220. }
  221. VOID ProcessChessboardClick(LPARAM lParam) {
  222.     LPNMITEMACTIVATE lpnmItem = (LPNMITEMACTIVATE)lParam;
  223.     LVHITTESTINFO hti = {0};
  224.     hti.pt.x = lpnmItem->ptAction.x;
  225.     hti.pt.y = lpnmItem->ptAction.y;
  226.     INT col = lpnmItem->iSubItem;
  227.     INT row = ListView_SubItemHitTest(chessboard, &hti);
  228.     WCHAR cn[] = L"a1";
  229.     if (IsCellInsideBoard(col, row)) {
  230.         MessageBoxW(NULL, PosToChessNotation(col, row, cn), L"Info", MB_OK);
  231.     }
  232. }
  233. LPWSTR PosToChessNotation(INT col, INT row, LPWSTR out) {
  234.     WCHAR c[] = L"a";
  235.     ColToChessNotation(col, c);
  236.     WCHAR r[] = L"1";
  237.     RowToChessNotation(row, r);
  238.     swprintf(out, L"%s%s", c, r);
  239.     return out;
  240. }
  241. LPWSTR ColToChessNotation(INT col, LPWSTR out) {
  242.     col += 'a' - CHESSBOARD_1ST_COL;
  243.     swprintf(out, L"%c", col);
  244.     return out;
  245. }
  246. LPWSTR RowToChessNotation(INT row, LPWSTR out) {
  247.     row = CHESSBOARD_LAST_ROW - row + 1;
  248.     swprintf(out, L"%d", row);
  249.     return out;
  250. }
  251. BOOL IsCellInsideBoard(INT col, INT row) {
  252.     return ((col >= CHESSBOARD_1ST_COL) && (col <= CHESSBOARD_LAST_COL) &&
  253.             (row >= CHESSBOARD_1ST_ROW) && (row <= CHESSBOARD_LAST_ROW));
  254. }
  255. HWND CreateStringGrid(HWND parent, INT id, HFONT font) {
  256.     HWND result = CreateWindowW(WC_LISTVIEWW, L"",
  257.         WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_NOCOLUMNHEADER,
  258.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parent,
  259.         (HMENU)id, instance, NULL);
  260.     StringGridChangeFont(result, font);
  261.     return result;
  262. }
  263. VOID StringGridChangeFont(HWND sg, HFONT font) {
  264.     SendMessageW(sg, WM_SETFONT, (WPARAM)font, (LPARAM)0);
  265. }
  266. VOID StringGridAddCol(HWND sg) {
  267.     LVCOLUMNW lvCol = {0};
  268.     lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_FMT;
  269.     lvCol.fmt = LVCFMT_CENTER;  // align text in cell
  270.     lvCol.pszText = NULL;
  271.     lvCol.cx = CELL_SIZE;
  272.     SendMessageW(sg, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvCol);
  273. }
  274. VOID StringGridAddRow(HWND sg) {
  275.     static LVITEMW lvItem = {0};
  276.     lvItem.mask = LVIF_TEXT;  // text style
  277.     lvItem.cchTextMax = MAX_STR_LEN;
  278.     lvItem.pszText = NULL;
  279.     SendMessageW(sg, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
  280. }
  281. VOID StringGridClear(HWND sg) {
  282.     for (int i = StringGridColCount(sg); i > 0; --i)
  283.         ListView_DeleteColumn(sg, 0);
  284.     ListView_DeleteAllItems(sg);
  285. }
  286. VOID StringGridResize(HWND sg, INT cols, INT rows) {
  287.     StringGridClear(sg);
  288.     for (INT i = 0; i < cols; ++i) {
  289.         StringGridAddCol(sg);
  290.     }
  291.     for (INT i = 0; i < rows; ++i) {
  292.         StringGridAddRow(sg);
  293.     }
  294. }
  295. SIZE StringGridAutoSize(HWND sg, INT rows) {
  296.     DWORD size = ListView_ApproximateViewRect(sg, -1, -1, rows);
  297.     SIZE result = {0};
  298.     result.cx = LOWORD(size);
  299.     result.cy = HIWORD(size);
  300.     ResizeWindow(sg, result.cx, result.cy);
  301.     return result;
  302. }
  303. INT StringGridColCount(HWND sg) {
  304.     return ListView_GetItemCount(sg);
  305. }
  306. INT StringGridSetItem(HWND sg, INT col, INT row, LPWSTR text) {
  307.     static LVITEMW lvItem = {0};
  308.     lvItem.mask = LVIF_TEXT;  // text style
  309.     lvItem.cchTextMax = MAX_STR_LEN;
  310.     lvItem.pszText = NULL;
  311.     lvItem.iSubItem = col;
  312.     lvItem.iItem = row;
  313.     lvItem.pszText = text;
  314.     SendMessageW(chessboard, LVM_SETITEMW, 0, (LPARAM)&lvItem);
  315. }
  316. VOID AutoSizeAll(VOID) {
  317.     SIZE sz = AutoSizeChessboard();
  318.     AutoSizeWindow(mainWin, sz);
  319. }
  320. SIZE AutoSizeChessboard(VOID) {
  321.     return StringGridAutoSize(chessboard, CHESSBOARD_ROWS - 1);
  322. }
  323. VOID AutoSizeWindow(HWND wnd, SIZE client) {
  324.     SIZE inner = GetWindowSize(wnd, TRUE);
  325.     SIZE outer = GetWindowSize(wnd, FALSE);
  326.     INT borderWidth = outer.cx - inner.cx;  // window decorations
  327.     INT borderHeight = outer.cy - inner.cy;  // decorations, header, menu
  328.     INT newWidth = client.cx + borderWidth;
  329.     INT newHeight = client.cy + borderHeight;
  330.     ResizeWindow(wnd, newWidth, newHeight);
  331. }
  332. HWND InitChessBoard(HWND wnd) {
  333.     InitFonts();
  334.     HWND result = CreateStringGrid(wnd, CHESSBOARD_ID, figuresFont);
  335.     StringGridResize(result, CHESSBOARD_COLS, CHESSBOARD_ROWS);
  336.     return result;
  337. }
  338. VOID UpdateChessBoard(VOID) {
  339.     WCHAR buffer[MAX_STR_LEN] = L" ";
  340.     UpdateChessBoardCaptions();
  341.     for (int y = 0; y < 8; ++y) {
  342.         for (int x = 0; x < 8; ++x) {
  343.             StringGridSetItem(chessboard,
  344.                 x + CHESSBOARD_1ST_COL, y + CHESSBOARD_1ST_ROW,
  345.                 CHESS_FIGURES_SMB[board[y][x]]);
  346.         }
  347.     }
  348. }
  349. VOID UpdateChessBoardCaptions(VOID) {
  350.     WCHAR buffer[] = L"a";
  351.     for (INT i = CHESSBOARD_1ST_COL; i < CHESSBOARD_1ST_COL + 8; ++i) {
  352.         ColToChessNotation(i, buffer);
  353.         StringGridSetItem(chessboard, i, CHESSBOARD_TOP_CAPTIONS, buffer);
  354.         StringGridSetItem(chessboard, i, CHESSBOARD_BOTTOM_CAPTIONS, buffer);
  355.     }
  356.     for (INT i = CHESSBOARD_1ST_ROW; i < CHESSBOARD_1ST_ROW + 8; ++i) {
  357.         RowToChessNotation(i, buffer);
  358.         StringGridSetItem(chessboard, CHESSBOARD_LEFT_CAPTIONS, i, buffer);
  359.         StringGridSetItem(chessboard, CHESSBOARD_RIGHT_CAPTIONS, i, buffer);
  360.     }
  361. }
  362. VOID ResetBoard(VOID) {
  363.     for (int y = 0; y < 8; ++y) {
  364.         for (int x = 0; x < 8; ++x) {
  365.             board[y][x] = START_POSITION[y][x];
  366.         }
  367.     }
  368. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement