Advertisement
alien_fx_fiend

PaintCanvas *FINAL RELEASE !*

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