Advertisement
alien_fx_fiend

PaintCanvas *FINAL RELEASE !*

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