Advertisement
alien_fx_fiend

PaintMemDC *FINAL RELEASE !*

Oct 22nd, 2024 (edited)
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.66 KB | Source Code | 0 0
  1. ==++"Splat.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 <locale>
  10. #include <windowsx.h>
  11. #include "resource.h"  // Add this with your other includes
  12.  
  13. using namespace std;
  14.  
  15. struct Brushstroke;
  16. HWND hWnd;
  17. HINSTANCE hInst;
  18. bool isDirty = false;
  19.  
  20. void SetWindowTitle(HWND hwnd, const std::wstring& filename) {
  21.     std::wstring title = L"Paint Canvas - " + filename + L" (P=Brush E=Eraser C=Clear +-=BrushSize Ctrl+S=Save Ctrl+O=Load)";
  22.     SetWindowText(hwnd, title.c_str());
  23. }
  24.  
  25. std::wstring StringToWString(const std::string& str) {
  26.     std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  27.     return converter.from_bytes(str);
  28. }
  29.  
  30. bool IsPointInClientRect(HWND hwnd, int x, int y) {
  31.     RECT rect;
  32.     GetClientRect(hwnd, &rect);
  33.     return (x >= 0 && x < rect.right&& y >= 0 && y < rect.bottom);
  34. }
  35.  
  36. struct Brushstroke {
  37.     int x;
  38.     int y;
  39.     int size;
  40.  
  41.     void serialize(ofstream& outFile) const {
  42.         outFile << "B " << x << " " << y << " " << size << endl;
  43.     }
  44. };
  45.  
  46. std::vector<Brushstroke> storedBrushstrokes;
  47. void RedrawStrokes();
  48. void SaveDrawing(const string& filename);
  49. void LoadDrawing(const string& filename);
  50.  
  51. HDC hdc, memDC;
  52. HBITMAP memBitmap;
  53. bool isPaintbrushSelected = true;
  54. bool isDrawing = false;
  55. bool isErasing = false;
  56. bool isClearing = false;
  57. bool isEraserSelected = false;
  58. int brushSize = 10;
  59.  
  60. void DrawBrush(HDC hdc, int x, int y) {
  61.     if (!IsPointInClientRect(hWnd, x, y)) return;
  62.     HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
  63.     HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
  64.     Rectangle(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  65.     DeleteObject(SelectObject(hdc, originalBrush));
  66.     DeleteObject(SelectObject(hdc, originalPen));
  67. }
  68.  
  69. void Erase(HDC hdc, int x, int y, int eraserSize) {
  70.     if (!IsPointInClientRect(hWnd, x, y)) return;
  71.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  72.     SelectObject(hdc, GetStockObject(NULL_PEN));
  73.     SelectObject(hdc, hBrush);
  74.     Rectangle(hdc, x - eraserSize, y - eraserSize, x + eraserSize, y + eraserSize);
  75.     DeleteObject(hBrush);
  76.  
  77.     storedBrushstrokes.erase(
  78.         std::remove_if(storedBrushstrokes.begin(), storedBrushstrokes.end(),
  79.             [x, y, eraserSize](const Brushstroke& stroke) {
  80.                 int dx = abs(stroke.x - x);
  81.                 int dy = abs(stroke.y - y);
  82.                 return (dx < eraserSize + stroke.size && dy < eraserSize + stroke.size);
  83.             }),
  84.         storedBrushstrokes.end()
  85.                 );
  86. }
  87.  
  88. void ClearDrawing(HWND hwnd) {
  89.     RECT rect;
  90.     GetClientRect(hwnd, &rect);
  91.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  92.     HDC hdc = GetDC(hwnd);
  93.     FillRect(hdc, &rect, hBrush);
  94.     FillRect(memDC, &rect, hBrush);
  95.     ReleaseDC(hwnd, hdc);
  96.     DeleteObject(hBrush);
  97.     storedBrushstrokes.clear();
  98.     InvalidateRect(hwnd, NULL, FALSE);
  99.     UpdateWindow(hwnd);
  100. }
  101.  
  102. void RedrawStrokes() {
  103.     RECT rect;
  104.     GetClientRect(hWnd, &rect);
  105.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  106.     FillRect(memDC, &rect, hBrush);
  107.     DeleteObject(hBrush);
  108.     for (const auto& brushstroke : storedBrushstrokes) {
  109.         HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(RGB(255, 0, 0)));
  110.         HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
  111.         Rectangle(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
  112.             brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
  113.         DeleteObject(SelectObject(memDC, originalBrush));
  114.         DeleteObject(SelectObject(memDC, originalPen));
  115.     }
  116.     InvalidateRect(hWnd, NULL, FALSE);
  117.     UpdateWindow(hWnd);
  118. }
  119.  
  120. void SaveDrawing(const string& filename) {
  121.     ofstream outFile(filename);
  122.     if (outFile.is_open()) {
  123.         outFile << storedBrushstrokes.size() << endl;
  124.         for (const auto& brushstroke : storedBrushstrokes) {
  125.             brushstroke.serialize(outFile);
  126.         }
  127.         outFile.close();
  128.         if (outFile.fail()) {
  129.             MessageBox(hWnd, L"Error occurred while saving the file", L"Save Error", MB_OK | MB_ICONERROR);
  130.         }
  131.         else {
  132.             isDirty = false;  // Reset the dirty flag after successful save
  133.         }
  134.     }
  135.     else {
  136.         MessageBox(hWnd, L"Could not open file for saving", L"Save Error", MB_OK | MB_ICONERROR);
  137.     }
  138. }
  139.  
  140. void LoadDrawing(const string& filename) {
  141.     ifstream inFile(filename);
  142.     if (inFile.is_open()) {
  143.         int numBrushstrokes;
  144.         inFile >> numBrushstrokes;
  145.         storedBrushstrokes.clear();
  146.         storedBrushstrokes.reserve(numBrushstrokes);
  147.         for (int i = 0; i < numBrushstrokes; ++i) {
  148.             char type;
  149.             Brushstroke brushstroke;
  150.             inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size;
  151.             storedBrushstrokes.push_back(brushstroke);
  152.         }
  153.         inFile.close();
  154.         RedrawStrokes();
  155.         isDirty = false;  // Inserted here
  156.     }
  157. }
  158.  
  159. void SaveDrawingDialog(HWND hwnd) {
  160.     OPENFILENAME ofn;
  161.     wchar_t szFileName[MAX_PATH] = L"";
  162.     ZeroMemory(&ofn, sizeof(ofn));
  163.     ofn.lStructSize = sizeof(ofn);
  164.     ofn.hwndOwner = hwnd;
  165.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  166.     ofn.lpstrFile = szFileName;
  167.     ofn.nMaxFile = MAX_PATH;
  168.     ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
  169.     ofn.lpstrDefExt = L"txt";
  170.     if (GetSaveFileName(&ofn)) {
  171.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  172.         std::string filenameStr = converter.to_bytes(szFileName);
  173.         SaveDrawing(filenameStr);
  174.         MessageBox(hwnd, L"Save Complete", L"Doodle App", MB_OK | MB_ICONINFORMATION);
  175.         SetWindowTitle(hwnd, szFileName);
  176.     }
  177. }
  178.  
  179. void LoadDrawingDialog(HWND hwnd) {
  180.     OPENFILENAME ofn;
  181.     wchar_t szFileName[MAX_PATH] = L"";
  182.     ZeroMemory(&ofn, sizeof(ofn));
  183.     ofn.lStructSize = sizeof(ofn);
  184.     ofn.hwndOwner = hwnd;
  185.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  186.     ofn.lpstrFile = szFileName;
  187.     ofn.nMaxFile = MAX_PATH;
  188.     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
  189.     if (GetOpenFileName(&ofn)) {
  190.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  191.         std::string filenameStr = converter.to_bytes(szFileName);
  192.         LoadDrawing(filenameStr);
  193.         SetWindowTitle(hwnd, szFileName);
  194.     }
  195. }
  196.  
  197. void SanitizeAndSaveDrawing(const string& filename) {
  198.     ofstream outFile(filename);
  199.     if (outFile.is_open()) {
  200.         RECT rect;
  201.         GetClientRect(hWnd, &rect);
  202.         vector<Brushstroke> validBrushstrokes;
  203.         for (const auto& brushstroke : storedBrushstrokes) {
  204.             if (IsPointInClientRect(hWnd, brushstroke.x, brushstroke.y)) {
  205.                 validBrushstrokes.push_back(brushstroke);
  206.             }
  207.         }
  208.         outFile << validBrushstrokes.size() << endl;
  209.         for (const auto& brushstroke : validBrushstrokes) {
  210.             brushstroke.serialize(outFile);
  211.         }
  212.         outFile.close();
  213.     }
  214. }
  215.  
  216. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  217.     switch (uMsg) {
  218.     case WM_CREATE:
  219.     {
  220.         hWnd = hwnd;
  221.         ShowWindow(hwnd, SW_MAXIMIZE);
  222.         RECT rect;
  223.         GetClientRect(hwnd, &rect);
  224.         HDC hdc = GetDC(hwnd);
  225.         memDC = CreateCompatibleDC(hdc);
  226.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  227.         SelectObject(memDC, memBitmap);
  228.         SetBkMode(memDC, TRANSPARENT);
  229.         FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
  230.         ReleaseDC(hwnd, hdc);
  231.         //SaveDrawing("drawing.txt");
  232.         CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
  233.         std::wstring initialFileName = L"drawing.txt";
  234.         if (pCreate && pCreate->lpCreateParams) {
  235.             initialFileName = *reinterpret_cast<std::wstring*>(pCreate->lpCreateParams);
  236.         }
  237.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  238.         std::string filenameStr = converter.to_bytes(initialFileName);
  239.         LoadDrawing(filenameStr);
  240.         SetWindowTitle(hwnd, initialFileName);
  241.         break;
  242.     }
  243.     case WM_PAINT:
  244.     {
  245.         PAINTSTRUCT ps;
  246.         HDC hdc = BeginPaint(hwnd, &ps);
  247.         BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
  248.             memDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
  249.         EndPaint(hwnd, &ps);
  250.         break;
  251.     }
  252.     case WM_LBUTTONDOWN:
  253.     {
  254.         isDrawing = true;
  255.         int x = GET_X_LPARAM(lParam);
  256.         int y = GET_Y_LPARAM(lParam);
  257.         if (isPaintbrushSelected) {
  258.             DrawBrush(memDC, x, y);
  259.             storedBrushstrokes.push_back({ x, y, brushSize });
  260.             isDirty = true;
  261.         }
  262.         else if (isEraserSelected) {
  263.             Erase(memDC, x, y, brushSize);
  264.             isDirty = true;
  265.         }
  266.         InvalidateRect(hwnd, NULL, FALSE);
  267.         break;
  268.     }
  269.     case WM_LBUTTONUP:
  270.         isDrawing = false;
  271.         break;
  272.     case WM_MOUSEMOVE:
  273.         if (isDrawing) {
  274.             int x = GET_X_LPARAM(lParam);
  275.             int y = GET_Y_LPARAM(lParam);
  276.             if (isPaintbrushSelected) {
  277.                 DrawBrush(memDC, x, y);
  278.                 storedBrushstrokes.push_back({ x, y, brushSize });
  279.                 isDirty = true;
  280.             }
  281.             else if (isEraserSelected) {
  282.                 Erase(memDC, x, y, brushSize);
  283.                 isDirty = true;
  284.             }
  285.             InvalidateRect(hwnd, NULL, FALSE);
  286.         }
  287.         break;
  288.     case WM_KEYDOWN:
  289.         switch (wParam) {
  290.             case VK_ESCAPE:
  291.                 if (isDirty) {
  292.                     int result = MessageBox(hwnd, L"Do you want to save your work before exiting?", L"Save Changes", MB_YESNOCANCEL | MB_ICONQUESTION);
  293.                     if (result == IDYES) {
  294.                         // Implement save functionality here
  295.                         SaveDrawing("painting.txt");
  296.                         // After saving, set g_isModified to false
  297.                         isDirty = false;
  298.                         PostQuitMessage(0);
  299.                     }
  300.                     else if (result == IDNO) {
  301.                         PostQuitMessage(0);
  302.                     }
  303.                     // If IDCANCEL, do nothing and return to the application
  304.                 }
  305.                 else {
  306.                     PostQuitMessage(0);
  307.                 }
  308.                 return 0;
  309.             //break;
  310.         //case VK_ESCAPE:
  311.             //PostQuitMessage(0);
  312.             //return 0;
  313.         case VK_F1:
  314.             MessageBox(hwnd, L"PaintMemDC 1.5 Programmed in C++ Win32 API (425 lines of code) by Entisoft Software\nCopyright (c) 2024 Evans Thorpemorton", L"Information", MB_OK | MB_ICONINFORMATION);
  315.             return 0;
  316.         case 'P':
  317.             isPaintbrushSelected = true;
  318.             isEraserSelected = false;
  319.             break;
  320.         case 'E':
  321.             isEraserSelected = true;
  322.             isPaintbrushSelected = false;
  323.             break;
  324.         case 'C':
  325.             isClearing = true;
  326.             ClearDrawing(hwnd);
  327.             isClearing = false;
  328.             isDirty = true;
  329.             break;
  330.         case VK_OEM_PLUS:
  331.             brushSize += 2;
  332.             break;
  333.         case VK_OEM_MINUS:
  334.             brushSize = max(1, brushSize - 2);
  335.             break;
  336.         case 'S':
  337.             if (GetKeyState(VK_CONTROL) & 0x8000) {
  338.                 SaveDrawingDialog(hwnd);
  339.             }
  340.             break;
  341.         case 'O':
  342.             if (GetKeyState(VK_CONTROL) & 0x8000) {
  343.                 LoadDrawingDialog(hwnd);
  344.             }
  345.             break;
  346.         //case VK_ESCAPE:
  347.             //SendMessage(hwnd, WM_CLOSE, 0, 0);
  348.             //break;
  349.         }
  350.         break;
  351.     case WM_SIZE:
  352.         if (wParam == SIZE_MAXIMIZED) {
  353.             RECT rect;
  354.             GetClientRect(hwnd, &rect);
  355.             HBITMAP newBitmap = CreateCompatibleBitmap(GetDC(hwnd), rect.right - rect.left, rect.bottom - rect.top);
  356.             SelectObject(memDC, newBitmap);
  357.             DeleteObject(memBitmap);
  358.             memBitmap = newBitmap;
  359.             RedrawStrokes();
  360.         }
  361.         break;
  362.     case WM_SETCURSOR:
  363.         if (LOWORD(lParam) == HTCLIENT) {
  364.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  365.             return TRUE;
  366.         }
  367.         break;
  368.     //Remove below function (added new)
  369.     case WM_CLOSE:
  370.         if (isDirty) {
  371.             int result = MessageBox(hwnd, L"Do you want to save your changes?", L"Doodle App", MB_YESNOCANCEL | MB_ICONQUESTION);
  372.             if (result == IDYES) {
  373.                 SaveDrawing("drawing.txt");
  374.             }
  375.             else if (result == IDCANCEL) {
  376.                 return 0;  // Don't close the window
  377.             }
  378.         }
  379.         DestroyWindow(hwnd);
  380.         break;
  381.         //original WM_DESTROY function below
  382.         /*if (isDirty) {
  383.             SaveDrawing("drawing.txt");
  384.         }
  385.         //SetWindowTitle(hwnd, L"drawing.txt");
  386.         PostQuitMessage(0);
  387.         break;*/
  388.  
  389.         //Ask to Save Changes new function below
  390.         /*if (isDirty) {
  391.             int result = MessageBox(hwnd, L"Do you want to save your changes?", L"Doodle App", MB_YESNOCANCEL | MB_ICONQUESTION);
  392.             if (result == IDYES) {
  393.                 SaveDrawing("drawing.txt");
  394.             }
  395.             else if (result == IDCANCEL) {
  396.                 return 0;  // Don't close the window
  397.             }
  398.         }
  399.         PostQuitMessage(0);
  400.         break;*/
  401.     case WM_DESTROY:        
  402.         PostQuitMessage(0);
  403.         break;
  404.     }
  405.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  406. }
  407.  
  408. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
  409.     hInst = hInstance;
  410.     const wchar_t CLASS_NAME[] = L"PaintCanvas";
  411.     WNDCLASS wc = {};
  412.     wc.lpfnWndProc = WindowProc;
  413.     wc.hInstance = hInstance;
  414.     wc.lpszClassName = CLASS_NAME;
  415.     wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));     // Add this line
  416.     RegisterClass(&wc);
  417.     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);
  418.     if (hwnd == NULL) {
  419.         return 0;
  420.     }
  421.     ShowWindow(hwnd, SW_MAXIMIZE);
  422.     MSG msg = {};
  423.     while (GetMessage(&msg, NULL, 0, 0)) {
  424.         TranslateMessage(&msg);
  425.         DispatchMessage(&msg);
  426.     }
  427.     return 0;
  428. }
  429.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement