Advertisement
alien_fx_fiend

Memory DC PaintCanvas Projectv15 [*FINAL*] (WORKING NO FRILLS ATTACHED !!!!)

Jul 15th, 2024 (edited)
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.88 KB | None | 0 0
  1. #include <vector>
  2. #include <windows.h>
  3. #include <fstream>
  4. #include <string>
  5. #include <commdlg.h>
  6. #include <codecvt>
  7. #include <algorithm>
  8. #include <locale>
  9. #include <windowsx.h>
  10.  
  11. using namespace std;
  12.  
  13. struct Brushstroke;
  14. HWND hWnd;
  15. HINSTANCE hInst;
  16.  
  17. void SetWindowTitle(HWND hwnd, const std::wstring& filename) {
  18.     std::wstring title = L"Paint Canvas - " + filename + L" (P=Brush E=Eraser C=Clear +-=BrushSize Ctrl+S=Save Ctrl+O=Load)";
  19.     SetWindowText(hwnd, title.c_str());
  20. }
  21.  
  22. std::wstring StringToWString(const std::string& str) {
  23.     std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  24.     return converter.from_bytes(str);
  25. }
  26.  
  27. bool IsPointInClientRect(HWND hwnd, int x, int y) {
  28.     RECT rect;
  29.     GetClientRect(hwnd, &rect);
  30.     return (x >= 0 && x < rect.right&& y >= 0 && y < rect.bottom);
  31. }
  32.  
  33. struct Brushstroke {
  34.     int x;
  35.     int y;
  36.     int size;
  37.  
  38.     void serialize(ofstream& outFile) const {
  39.         outFile << "B " << x << " " << y << " " << size << endl;
  40.     }
  41. };
  42.  
  43. std::vector<Brushstroke> storedBrushstrokes;
  44. void RedrawStrokes();
  45. void SaveDrawing(const string& filename);
  46. void LoadDrawing(const string& filename);
  47.  
  48. HDC hdc, memDC;
  49. HBITMAP memBitmap;
  50. bool isPaintbrushSelected = true;
  51. bool isDrawing = false;
  52. bool isErasing = false;
  53. bool isClearing = false;
  54. bool isEraserSelected = false;
  55. int brushSize = 10;
  56.  
  57. void DrawBrush(HDC hdc, int x, int y) {
  58.     if (!IsPointInClientRect(hWnd, x, y)) return;
  59.     HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
  60.     HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
  61.     Rectangle(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  62.     DeleteObject(SelectObject(hdc, originalBrush));
  63.     DeleteObject(SelectObject(hdc, originalPen));
  64. }
  65.  
  66. void Erase(HDC hdc, int x, int y, int eraserSize) {
  67.     if (!IsPointInClientRect(hWnd, x, y)) return;
  68.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  69.     SelectObject(hdc, GetStockObject(NULL_PEN));
  70.     SelectObject(hdc, hBrush);
  71.     Rectangle(hdc, x - eraserSize, y - eraserSize, x + eraserSize, y + eraserSize);
  72.     DeleteObject(hBrush);
  73.  
  74.     storedBrushstrokes.erase(
  75.         std::remove_if(storedBrushstrokes.begin(), storedBrushstrokes.end(),
  76.             [x, y, eraserSize](const Brushstroke& stroke) {
  77.                 int dx = abs(stroke.x - x);
  78.                 int dy = abs(stroke.y - y);
  79.                 return (dx < eraserSize + stroke.size && dy < eraserSize + stroke.size);
  80.             }),
  81.         storedBrushstrokes.end()
  82.                 );
  83. }
  84.  
  85. void ClearDrawing(HWND hwnd) {
  86.     RECT rect;
  87.     GetClientRect(hwnd, &rect);
  88.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  89.     HDC hdc = GetDC(hwnd);
  90.     FillRect(hdc, &rect, hBrush);
  91.     FillRect(memDC, &rect, hBrush);
  92.     ReleaseDC(hwnd, hdc);
  93.     DeleteObject(hBrush);
  94.     storedBrushstrokes.clear();
  95.     InvalidateRect(hwnd, NULL, FALSE);
  96.     UpdateWindow(hwnd);
  97. }
  98.  
  99. void RedrawStrokes() {
  100.     RECT rect;
  101.     GetClientRect(hWnd, &rect);
  102.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  103.     FillRect(memDC, &rect, hBrush);
  104.     DeleteObject(hBrush);
  105.     for (const auto& brushstroke : storedBrushstrokes) {
  106.         HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(RGB(255, 0, 0)));
  107.         HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
  108.         Rectangle(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
  109.             brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
  110.         DeleteObject(SelectObject(memDC, originalBrush));
  111.         DeleteObject(SelectObject(memDC, originalPen));
  112.     }
  113.     InvalidateRect(hWnd, NULL, FALSE);
  114.     UpdateWindow(hWnd);
  115. }
  116.  
  117. void SaveDrawing(const string& filename) {
  118.     ofstream outFile(filename);
  119.     if (outFile.is_open()) {
  120.         outFile << storedBrushstrokes.size() << endl;
  121.         for (const auto& brushstroke : storedBrushstrokes) {
  122.             brushstroke.serialize(outFile);
  123.         }
  124.         outFile.close();
  125.         if (outFile.fail()) {
  126.             MessageBox(hWnd, L"Error occurred while saving the file", L"Save Error", MB_OK | MB_ICONERROR);
  127.         }
  128.     }
  129.     else {
  130.         MessageBox(hWnd, L"Could not open file for saving", L"Save Error", MB_OK | MB_ICONERROR);
  131.     }
  132. }
  133.  
  134. void LoadDrawing(const string& filename) {
  135.     ifstream inFile(filename);
  136.     if (inFile.is_open()) {
  137.         int numBrushstrokes;
  138.         inFile >> numBrushstrokes;
  139.         storedBrushstrokes.clear();
  140.         storedBrushstrokes.reserve(numBrushstrokes);
  141.         for (int i = 0; i < numBrushstrokes; ++i) {
  142.             char type;
  143.             Brushstroke brushstroke;
  144.             inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size;
  145.             storedBrushstrokes.push_back(brushstroke);
  146.         }
  147.         inFile.close();
  148.         RedrawStrokes();
  149.     }
  150. }
  151.  
  152. void SaveDrawingDialog(HWND hwnd) {
  153.     OPENFILENAME ofn;
  154.     wchar_t szFileName[MAX_PATH] = L"";
  155.     ZeroMemory(&ofn, sizeof(ofn));
  156.     ofn.lStructSize = sizeof(ofn);
  157.     ofn.hwndOwner = hwnd;
  158.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  159.     ofn.lpstrFile = szFileName;
  160.     ofn.nMaxFile = MAX_PATH;
  161.     ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
  162.     ofn.lpstrDefExt = L"txt";
  163.     if (GetSaveFileName(&ofn)) {
  164.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  165.         std::string filenameStr = converter.to_bytes(szFileName);
  166.         SaveDrawing(filenameStr);
  167.         MessageBox(hwnd, L"Save Complete", L"Doodle App", MB_OK | MB_ICONINFORMATION);
  168.         SetWindowTitle(hwnd, szFileName);
  169.     }
  170. }
  171.  
  172. void LoadDrawingDialog(HWND hwnd) {
  173.     OPENFILENAME ofn;
  174.     wchar_t szFileName[MAX_PATH] = L"";
  175.     ZeroMemory(&ofn, sizeof(ofn));
  176.     ofn.lStructSize = sizeof(ofn);
  177.     ofn.hwndOwner = hwnd;
  178.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  179.     ofn.lpstrFile = szFileName;
  180.     ofn.nMaxFile = MAX_PATH;
  181.     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
  182.     if (GetOpenFileName(&ofn)) {
  183.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  184.         std::string filenameStr = converter.to_bytes(szFileName);
  185.         LoadDrawing(filenameStr);
  186.         SetWindowTitle(hwnd, szFileName);
  187.     }
  188. }
  189.  
  190. void SanitizeAndSaveDrawing(const string& filename) {
  191.     ofstream outFile(filename);
  192.     if (outFile.is_open()) {
  193.         RECT rect;
  194.         GetClientRect(hWnd, &rect);
  195.         vector<Brushstroke> validBrushstrokes;
  196.         for (const auto& brushstroke : storedBrushstrokes) {
  197.             if (IsPointInClientRect(hWnd, brushstroke.x, brushstroke.y)) {
  198.                 validBrushstrokes.push_back(brushstroke);
  199.             }
  200.         }
  201.         outFile << validBrushstrokes.size() << endl;
  202.         for (const auto& brushstroke : validBrushstrokes) {
  203.             brushstroke.serialize(outFile);
  204.         }
  205.         outFile.close();
  206.     }
  207. }
  208.  
  209. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  210.     switch (uMsg) {
  211.     case WM_CREATE:
  212.     {
  213.         hWnd = hwnd;
  214.         ShowWindow(hwnd, SW_MAXIMIZE);
  215.         RECT rect;
  216.         GetClientRect(hwnd, &rect);
  217.         HDC hdc = GetDC(hwnd);
  218.         memDC = CreateCompatibleDC(hdc);
  219.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  220.         SelectObject(memDC, memBitmap);
  221.         SetBkMode(memDC, TRANSPARENT);
  222.         FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
  223.         ReleaseDC(hwnd, hdc);
  224.         //SaveDrawing("drawing.txt");
  225.         CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
  226.         std::wstring initialFileName = L"drawing.txt";
  227.         if (pCreate && pCreate->lpCreateParams) {
  228.             initialFileName = *reinterpret_cast<std::wstring*>(pCreate->lpCreateParams);
  229.         }
  230.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  231.         std::string filenameStr = converter.to_bytes(initialFileName);
  232.         LoadDrawing(filenameStr);
  233.         SetWindowTitle(hwnd, initialFileName);
  234.         break;
  235.     }
  236.     case WM_PAINT:
  237.     {
  238.         PAINTSTRUCT ps;
  239.         HDC hdc = BeginPaint(hwnd, &ps);
  240.         BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
  241.             memDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
  242.         EndPaint(hwnd, &ps);
  243.         break;
  244.     }
  245.     case WM_LBUTTONDOWN:
  246.     {
  247.         isDrawing = true;
  248.         int x = GET_X_LPARAM(lParam);
  249.         int y = GET_Y_LPARAM(lParam);
  250.         if (isPaintbrushSelected) {
  251.             DrawBrush(memDC, x, y);
  252.             storedBrushstrokes.push_back({ x, y, brushSize });
  253.         }
  254.         else if (isEraserSelected) {
  255.             Erase(memDC, x, y, brushSize);
  256.         }
  257.         InvalidateRect(hwnd, NULL, FALSE);
  258.         break;
  259.     }
  260.     case WM_LBUTTONUP:
  261.         isDrawing = false;
  262.         break;
  263.     case WM_MOUSEMOVE:
  264.         if (isDrawing) {
  265.             int x = GET_X_LPARAM(lParam);
  266.             int y = GET_Y_LPARAM(lParam);
  267.             if (isPaintbrushSelected) {
  268.                 DrawBrush(memDC, x, y);
  269.                 storedBrushstrokes.push_back({ x, y, brushSize });
  270.             }
  271.             else if (isEraserSelected) {
  272.                 Erase(memDC, x, y, brushSize);
  273.             }
  274.             InvalidateRect(hwnd, NULL, FALSE);
  275.         }
  276.         break;
  277.     case WM_KEYDOWN:
  278.         switch (wParam) {
  279.         case 'P':
  280.             isPaintbrushSelected = true;
  281.             isEraserSelected = false;
  282.             break;
  283.         case 'E':
  284.             isEraserSelected = true;
  285.             isPaintbrushSelected = false;
  286.             break;
  287.         case 'C':
  288.             isClearing = true;
  289.             ClearDrawing(hwnd);
  290.             isClearing = false;
  291.             break;
  292.         case VK_OEM_PLUS:
  293.             brushSize += 2;
  294.             break;
  295.         case VK_OEM_MINUS:
  296.             brushSize = max(1, brushSize - 2);
  297.             break;
  298.         case 'S':
  299.             if (GetKeyState(VK_CONTROL) & 0x8000) {
  300.                 SaveDrawingDialog(hwnd);
  301.             }
  302.             break;
  303.         case 'O':
  304.             if (GetKeyState(VK_CONTROL) & 0x8000) {
  305.                 LoadDrawingDialog(hwnd);
  306.             }
  307.             break;
  308.         case VK_ESCAPE:
  309.             SendMessage(hwnd, WM_CLOSE, 0, 0);
  310.             break;
  311.         }
  312.         break;
  313.     case WM_SIZE:
  314.         if (wParam == SIZE_MAXIMIZED) {
  315.             RECT rect;
  316.             GetClientRect(hwnd, &rect);
  317.             HBITMAP newBitmap = CreateCompatibleBitmap(GetDC(hwnd), rect.right - rect.left, rect.bottom - rect.top);
  318.             SelectObject(memDC, newBitmap);
  319.             DeleteObject(memBitmap);
  320.             memBitmap = newBitmap;
  321.             RedrawStrokes();
  322.         }
  323.         break;
  324.     case WM_SETCURSOR:
  325.         if (LOWORD(lParam) == HTCLIENT) {
  326.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  327.             return TRUE;
  328.         }
  329.         break;
  330.     case WM_DESTROY:
  331.         SaveDrawing("drawing.txt");
  332.         //SetWindowTitle(hwnd, L"drawing.txt");
  333.         PostQuitMessage(0);
  334.         break;
  335.     }
  336.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  337. }
  338.  
  339. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
  340.     hInst = hInstance;
  341.     const wchar_t CLASS_NAME[] = L"PaintCanvas";
  342.     WNDCLASS wc = {};
  343.     wc.lpfnWndProc = WindowProc;
  344.     wc.hInstance = hInstance;
  345.     wc.lpszClassName = CLASS_NAME;
  346.     RegisterClass(&wc);
  347.     HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Paint Canvas (P=Brush E=Eraser C=Clear +-=BrushSize Ctrl+S=Save Ctrl+O=Load)", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  348.     if (hwnd == NULL) {
  349.         return 0;
  350.     }
  351.     ShowWindow(hwnd, SW_MAXIMIZE);
  352.     MSG msg = {};
  353.     while (GetMessage(&msg, NULL, 0, 0)) {
  354.         TranslateMessage(&msg);
  355.         DispatchMessage(&msg);
  356.     }
  357.     return 0;
  358. }
  359.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement