Advertisement
alien_fx_fiend

Memory DC PaintCanvasv11 Final Test (ClearDrawing working again All Fixed!!)

Jul 12th, 2024 (edited)
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.99 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.  
  9. using namespace std;
  10.  
  11. struct Brushstroke;
  12. struct Eraserstroke;
  13. HWND hWnd;
  14. HINSTANCE hInst;
  15. bool IsPointInClientRect(HWND hwnd, int x, int y) {
  16.     RECT rect;
  17.     GetClientRect(hwnd, &rect);
  18.     return (x >= 0 && x < rect.right&& y >= 0 && y < rect.bottom);
  19. }
  20.  
  21. struct Brushstroke {
  22.     int x;
  23.     int y;
  24.     int size;
  25.     COLORREF color;
  26.     void serialize(ofstream& outFile) const {
  27.         outFile << "B " << x << " " << y << " " << size << " "
  28.             << (int)GetRValue(color) << " "
  29.             << (int)GetGValue(color) << " "
  30.             << (int)GetBValue(color) << endl;
  31.     }
  32. };
  33.  
  34. struct Eraserstroke {
  35.     int x;
  36.     int y;
  37.     int size;
  38.     COLORREF color;
  39.     void serialize(ofstream& outFile) const {
  40.         outFile << "E " << x << " " << y << " " << size << endl;
  41.     }
  42. };
  43.  
  44. std::vector<Brushstroke> storedBrushstrokes;
  45. std::vector<Eraserstroke> storedEraserstrokes;
  46.  
  47. void RedrawStrokes();
  48. void SaveDrawing(const string& filename);
  49. void LoadDrawing(const string& filename);
  50.  
  51. POINT previousPoint;
  52. HDC hdc, memDC;
  53. HBITMAP memBitmap;
  54.  
  55. bool isPaintbrushSelected = true;
  56. bool isDrawing = false;
  57. bool isErasing = false;
  58. bool isClearing = false;
  59. bool isEraserSelected = false;
  60. int brushSize = 10;
  61.  
  62. void DrawBrush(HDC hdc, int x, int y) {
  63.     if (!IsPointInClientRect(hWnd, x, y)) return;
  64.     HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
  65.     HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
  66.     Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  67.     DeleteObject(SelectObject(hdc, originalBrush));
  68.     DeleteObject(SelectObject(hdc, originalPen));
  69. }
  70.  
  71. void Erase(HDC hdc, int x, int y, int eraserSize) {
  72.     if (!IsPointInClientRect(hWnd, x, y)) return;
  73.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  74.     SelectObject(hdc, GetStockObject(NULL_PEN));
  75.     SelectObject(hdc, hBrush);
  76.     Ellipse(hdc, x - eraserSize, y - eraserSize, x + eraserSize, y + eraserSize);
  77.     DeleteObject(hBrush);
  78.  
  79.     // Remove brushstrokes that intersect with the eraser
  80.     storedBrushstrokes.erase(
  81.         std::remove_if(storedBrushstrokes.begin(), storedBrushstrokes.end(),
  82.             [x, y, eraserSize](const Brushstroke& stroke) {
  83.                 int dx = stroke.x - x;
  84.                 int dy = stroke.y - y;
  85.                 return (dx * dx + dy * dy) <= (eraserSize + stroke.size) * (eraserSize + stroke.size);
  86.             }),
  87.         storedBrushstrokes.end()
  88.                 );
  89. }
  90.  
  91. // Update the ClearDrawing function
  92. void ClearDrawing(HWND hwnd) {
  93.     RECT rect;
  94.     GetClientRect(hwnd, &rect);
  95.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  96.  
  97.     // Clear both hdc AND memDC
  98.     HDC hdc = GetDC(hwnd);
  99.     FillRect(hdc, &rect, hBrush);
  100.     FillRect(memDC, &rect, hBrush);
  101.     ReleaseDC(hwnd, hdc);
  102.  
  103.     DeleteObject(hBrush);
  104.     storedBrushstrokes.clear();
  105.  
  106.     InvalidateRect(hwnd, NULL, FALSE);
  107.     UpdateWindow(hwnd);
  108. }
  109.  
  110. void DrawSmoothBrush(HDC hdc, int x, int y) {
  111.     if (isDrawing && (isPaintbrushSelected || isEraserSelected)) {
  112.         int numPoints = 3;
  113.         POINT currentPoint = { x, y };
  114.         for (int i = 1; i <= numPoints; i++) {
  115.             float t = (float)i / (float)numPoints;
  116.             int smoothX = (int)(previousPoint.x + t * (currentPoint.x - previousPoint.x));
  117.             int smoothY = (int)(previousPoint.y + t * (currentPoint.y - previousPoint.y));
  118.             if (isPaintbrushSelected) {
  119.                 DrawBrush(hdc, smoothX, smoothY);
  120.                 Brushstroke newBrushstroke;
  121.                 newBrushstroke.x = smoothX;
  122.                 newBrushstroke.y = smoothY;
  123.                 newBrushstroke.size = brushSize;
  124.                 newBrushstroke.color = RGB(255, 0, 0);
  125.                 storedBrushstrokes.push_back(newBrushstroke);
  126.             }
  127.             else if (isEraserSelected) {
  128.                 Erase(hdc, smoothX, smoothY, brushSize);
  129.                 Eraserstroke newEraserstroke;
  130.                 newEraserstroke.x = smoothX;
  131.                 newEraserstroke.y = smoothY;
  132.                 newEraserstroke.size = brushSize;
  133.                 newEraserstroke.color = RGB(255, 255, 255);
  134.                 storedEraserstrokes.push_back(newEraserstroke);
  135.             }
  136.         }
  137.         previousPoint = currentPoint;
  138.     }
  139. }
  140.  
  141. void RedrawStrokes() {
  142.     // Clear the entire drawing area
  143.     RECT rect;
  144.     GetClientRect(hWnd, &rect);
  145.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  146.     FillRect(memDC, &rect, hBrush);
  147.     DeleteObject(hBrush);
  148.  
  149.     // Redraw all brushstrokes
  150.     for (const auto& brushstroke : storedBrushstrokes) {
  151.         HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(brushstroke.color));
  152.         HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
  153.         Ellipse(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
  154.             brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
  155.         DeleteObject(SelectObject(memDC, originalBrush));
  156.         DeleteObject(SelectObject(memDC, originalPen));
  157.     }
  158. }
  159.  
  160. void SaveDrawing(const string& filename) {
  161.     ofstream outFile(filename);
  162.     if (outFile.is_open()) {
  163.         outFile << storedBrushstrokes.size() << endl;
  164.         for (const auto& brushstroke : storedBrushstrokes) {
  165.             brushstroke.serialize(outFile);
  166.         }
  167.         outFile.close();
  168.     }
  169. }
  170.  
  171. void LoadDrawing(const string& filename) {
  172.     ifstream inFile(filename);
  173.     if (inFile.is_open()) {
  174.         int numBrushstrokes;
  175.         inFile >> numBrushstrokes;
  176.         storedBrushstrokes.clear();
  177.         storedBrushstrokes.reserve(numBrushstrokes);
  178.         for (int i = 0; i < numBrushstrokes; ++i) {
  179.             char type;
  180.             Brushstroke brushstroke;
  181.             int r, g, b;
  182.             inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size >> r >> g >> b;
  183.             brushstroke.color = RGB(r, g, b);
  184.             storedBrushstrokes.push_back(brushstroke);
  185.         }
  186.         inFile.close();
  187.         // Clear memDC before redrawing
  188.         RECT rect;
  189.         GetClientRect(hWnd, &rect);
  190.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  191.         FillRect(memDC, &rect, hBrush);
  192.         DeleteObject(hBrush);
  193.         RedrawStrokes();
  194.         InvalidateRect(hWnd, NULL, TRUE);
  195.     }
  196. }
  197.  
  198. void SaveDrawingDialog(HWND hwnd) {
  199.     OPENFILENAME ofn;
  200.     wchar_t szFileName[MAX_PATH] = L"";
  201.  
  202.     ZeroMemory(&ofn, sizeof(ofn));
  203.     ofn.lStructSize = sizeof(ofn);
  204.     ofn.hwndOwner = hwnd;
  205.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  206.     ofn.lpstrFile = szFileName;
  207.     ofn.nMaxFile = MAX_PATH;
  208.     ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
  209.     ofn.lpstrDefExt = L"txt";
  210.  
  211.     if (GetSaveFileName(&ofn)) {
  212.         std::wstring_convert < std::codecvt_utf8 < wchar_t>> converter;
  213.         std::string filenameStr = converter.to_bytes(szFileName);
  214.         SaveDrawing(filenameStr);
  215.         MessageBox(hwnd, L"Save Complete", L"Doodle App", MB_OK | MB_ICONINFORMATION);
  216.     }
  217. }
  218.  
  219. void LoadDrawingDialog(HWND hwnd) {
  220.     OPENFILENAME ofn;
  221.     wchar_t szFileName[MAX_PATH] = L"";
  222.  
  223.     ZeroMemory(&ofn, sizeof(ofn));
  224.     ofn.lStructSize = sizeof(ofn);
  225.     ofn.hwndOwner = hwnd;
  226.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  227.     ofn.lpstrFile = szFileName;
  228.     ofn.nMaxFile = MAX_PATH;
  229.     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
  230.  
  231.     if (GetOpenFileName(&ofn)) {
  232.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  233.         std::string filenameStr = converter.to_bytes(szFileName);
  234.         LoadDrawing(filenameStr);
  235.     }
  236. }
  237.  
  238. void SanitizeAndSaveDrawing(const string& filename) {
  239.     ofstream outFile(filename);
  240.     if (outFile.is_open()) {
  241.         RECT rect;
  242.         GetClientRect(hWnd, &rect);
  243.  
  244.         vector<Brushstroke> validBrushstrokes;
  245.         for (const auto& brushstroke : storedBrushstrokes) {
  246.             if (IsPointInClientRect(hWnd, brushstroke.x, brushstroke.y)) {
  247.                 validBrushstrokes.push_back(brushstroke);
  248.             }
  249.         }
  250.  
  251.         outFile << validBrushstrokes.size() << endl;
  252.         for (const auto& brushstroke : validBrushstrokes) {
  253.             brushstroke.serialize(outFile);
  254.         }
  255.         outFile.close();
  256.     }
  257. }
  258. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  259.     switch (uMsg) {
  260.     case WM_CREATE:
  261.     {
  262.         hWnd = hwnd;
  263.         RECT rect;
  264.         GetClientRect(hwnd, &rect);
  265.         HDC hdc = GetDC(hwnd);
  266.         memDC = CreateCompatibleDC(hdc);
  267.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  268.         SelectObject(memDC, memBitmap);
  269.         ReleaseDC(hwnd, hdc);
  270.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  271.         FillRect(memDC, &rect, hBrush);
  272.         DeleteObject(hBrush);
  273.         isPaintbrushSelected = true;
  274.         LoadDrawing("drawing.txt");
  275.     }
  276.     break;
  277.     case WM_KEYDOWN:
  278.         if (wParam == VK_ADD) {
  279.             brushSize += 5;
  280.         }
  281.         else if (wParam == VK_SUBTRACT) {
  282.             if (brushSize > 5) {
  283.                 brushSize -= 5;
  284.             }
  285.         }
  286.         else if (wParam == 0x43) { // 'C' key
  287.             if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
  288.                 ClearDrawing(hwnd);
  289.             }
  290.         }
  291.         else if (wParam == 0x50) {
  292.             isPaintbrushSelected = true;
  293.             isEraserSelected = false;
  294.         }
  295.         else if (wParam == 0x45) {
  296.             isEraserSelected = true;
  297.             isPaintbrushSelected = false;
  298.         }
  299.         else if (wParam == 'S' && (GetKeyState(VK_CONTROL) & 0x8000)) {
  300.             SaveDrawingDialog(hwnd);
  301.         }
  302.         else if (wParam == 'O' && (GetKeyState(VK_CONTROL) & 0x8000)) {
  303.             LoadDrawingDialog(hwnd);
  304.         }
  305.         break;
  306.     case WM_LBUTTONDOWN:
  307.         if (isPaintbrushSelected || isEraserSelected) {
  308.             previousPoint.x = LOWORD(lParam);
  309.             previousPoint.y = HIWORD(lParam);
  310.         }
  311.         isDrawing = true;
  312.         break;
  313.     case WM_LBUTTONUP:
  314.         isDrawing = false;
  315.         break;
  316.     case WM_MOUSEMOVE:
  317.         if (isDrawing && isPaintbrushSelected) {
  318.             int x = LOWORD(lParam);
  319.             int y = HIWORD(lParam);
  320.             DrawSmoothBrush(memDC, x, y);
  321.             InvalidateRect(hwnd, NULL, FALSE);
  322.             if (IsPointInClientRect(hWnd, x, y)) {
  323.                 Brushstroke newBrushstroke;
  324.                 newBrushstroke.x = x;
  325.                 newBrushstroke.y = y;
  326.                 newBrushstroke.size = brushSize;
  327.                 newBrushstroke.color = RGB(255, 0, 0);
  328.                 storedBrushstrokes.push_back(newBrushstroke);
  329.             }
  330.         }
  331.         else if (isDrawing && isEraserSelected) {
  332.             int x = LOWORD(lParam);
  333.             int y = HIWORD(lParam);
  334.             Erase(memDC, x, y, brushSize);
  335.             InvalidateRect(hwnd, NULL, FALSE);
  336.         }
  337.         break;
  338.     case WM_SIZE:
  339.     {
  340.         static bool isMinimized = false;
  341.         if (wParam == SIZE_MINIMIZED)
  342.         {
  343.             isMinimized = true;
  344.         }
  345.         else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
  346.         {
  347.             if (isMinimized)
  348.             {
  349.                 isMinimized = false;
  350.             }
  351.             InvalidateRect(hwnd, NULL, TRUE);
  352.         }
  353.         RECT rect;
  354.         GetClientRect(hwnd, &rect);
  355.         if (memDC)
  356.         {
  357.             DeleteDC(memDC);
  358.             DeleteObject(memBitmap);
  359.         }
  360.         HDC hdc = GetDC(hwnd);
  361.         memDC = CreateCompatibleDC(hdc);
  362.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  363.         SelectObject(memDC, memBitmap);
  364.         ReleaseDC(hwnd, hdc);
  365.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  366.         FillRect(memDC, &rect, hBrush);
  367.         DeleteObject(hBrush);
  368.         RedrawStrokes();
  369.     }
  370.     break;
  371.     case WM_PAINT:
  372.     {
  373.         PAINTSTRUCT ps;
  374.         HDC hdc = BeginPaint(hwnd, &ps);
  375.         BitBlt(hdc, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, memDC, 0, 0, SRCCOPY);
  376.         EndPaint(hwnd, &ps);
  377.     }
  378.     break;
  379.     case WM_SETCURSOR:
  380.         if (LOWORD(lParam) == HTCLIENT) {
  381.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  382.             return TRUE;
  383.         }
  384.         break;
  385.     case WM_CLOSE:
  386.         // Sanitize and save before closing
  387.         SanitizeAndSaveDrawing("drawing.txt");
  388.         DestroyWindow(hwnd);
  389.         break;
  390.     case WM_DESTROY:
  391.         DeleteDC(memDC);
  392.         DeleteObject(memBitmap);
  393.         PostQuitMessage(0);
  394.         break;
  395.     default:
  396.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  397.     }
  398. }
  399.  
  400. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  401.     const wchar_t CLASS_NAME[] = L"PaintCanvasWindowClass";
  402.     WNDCLASS wc = { };
  403.  
  404.     wc.lpfnWndProc = WindowProc;
  405.     wc.hInstance = hInstance;
  406.     wc.lpszClassName = CLASS_NAME;
  407.  
  408.     RegisterClass(&wc);
  409.     HWND hwnd = CreateWindowEx(
  410.         0,                              // Optional window styles
  411.         CLASS_NAME,                     // Window class
  412.         L"Paint Canvas (P=Brush E=Eraser C=Clear +-=BrushSize Ctrl+S=Save Ctrl+O=Load)",            // Window text
  413.         WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,            // Window style
  414.  
  415.         // Size and position
  416.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  417.  
  418.         NULL,       // Parent window    
  419.         NULL,       // Menu
  420.         hInstance,  // Instance handle
  421.         NULL        // Additional application data
  422.     );
  423.  
  424.     if (hwnd == NULL) {
  425.         return 0;
  426.     }
  427.  
  428.     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
  429.     // Run the message loop
  430.     MSG msg = { };
  431.     while (GetMessage(&msg, NULL, 0, 0)) {
  432.         TranslateMessage(&msg);
  433.         DispatchMessage(&msg);
  434.     }
  435.  
  436.     return 0;
  437. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement