Advertisement
alien_fx_fiend

PaintMemDC *FINAL RELEASE !*

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