Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ==++"Splat.cpp" File 1/1 SourceCode::++==
- #include <vector>
- #include <windows.h>
- #include <fstream>
- #include <string>
- #include <commdlg.h>
- #include <codecvt>
- #include <algorithm>
- #include <locale>
- #include <windowsx.h>
- #include "resource.h" // Add this with your other includes
- using namespace std;
- struct Brushstroke;
- HWND hWnd;
- HINSTANCE hInst;
- bool isDirty = false;
- void SetWindowTitle(HWND hwnd, const std::wstring& filename) {
- std::wstring title = L"Paint Canvas - " + filename + L" (P=Brush E=Eraser C=Clear +-=BrushSize Ctrl+S=Save Ctrl+O=Load)";
- SetWindowText(hwnd, title.c_str());
- }
- std::wstring StringToWString(const std::string& str) {
- std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
- return converter.from_bytes(str);
- }
- bool IsPointInClientRect(HWND hwnd, int x, int y) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- return (x >= 0 && x < rect.right&& y >= 0 && y < rect.bottom);
- }
- struct Brushstroke {
- int x;
- int y;
- int size;
- void serialize(ofstream& outFile) const {
- outFile << "B " << x << " " << y << " " << size << endl;
- }
- };
- std::vector<Brushstroke> storedBrushstrokes;
- void RedrawStrokes();
- void SaveDrawing(const string& filename);
- void LoadDrawing(const string& filename);
- HDC hdc, memDC;
- HBITMAP memBitmap;
- bool isPaintbrushSelected = true;
- bool isDrawing = false;
- bool isErasing = false;
- bool isClearing = false;
- bool isEraserSelected = false;
- int brushSize = 10;
- void DrawBrush(HDC hdc, int x, int y) {
- if (!IsPointInClientRect(hWnd, x, y)) return;
- HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
- HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
- Rectangle(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- DeleteObject(SelectObject(hdc, originalBrush));
- DeleteObject(SelectObject(hdc, originalPen));
- }
- void Erase(HDC hdc, int x, int y, int eraserSize) {
- if (!IsPointInClientRect(hWnd, x, y)) return;
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, GetStockObject(NULL_PEN));
- SelectObject(hdc, hBrush);
- Rectangle(hdc, x - eraserSize, y - eraserSize, x + eraserSize, y + eraserSize);
- DeleteObject(hBrush);
- storedBrushstrokes.erase(
- std::remove_if(storedBrushstrokes.begin(), storedBrushstrokes.end(),
- [x, y, eraserSize](const Brushstroke& stroke) {
- int dx = abs(stroke.x - x);
- int dy = abs(stroke.y - y);
- return (dx < eraserSize + stroke.size && dy < eraserSize + stroke.size);
- }),
- storedBrushstrokes.end()
- );
- }
- void ClearDrawing(HWND hwnd) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- HDC hdc = GetDC(hwnd);
- FillRect(hdc, &rect, hBrush);
- FillRect(memDC, &rect, hBrush);
- ReleaseDC(hwnd, hdc);
- DeleteObject(hBrush);
- storedBrushstrokes.clear();
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateWindow(hwnd);
- }
- void RedrawStrokes() {
- RECT rect;
- GetClientRect(hWnd, &rect);
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(memDC, &rect, hBrush);
- DeleteObject(hBrush);
- for (const auto& brushstroke : storedBrushstrokes) {
- HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(RGB(255, 0, 0)));
- HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
- Rectangle(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
- brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
- DeleteObject(SelectObject(memDC, originalBrush));
- DeleteObject(SelectObject(memDC, originalPen));
- }
- InvalidateRect(hWnd, NULL, FALSE);
- UpdateWindow(hWnd);
- }
- void SaveDrawing(const string& filename) {
- ofstream outFile(filename);
- if (outFile.is_open()) {
- outFile << storedBrushstrokes.size() << endl;
- for (const auto& brushstroke : storedBrushstrokes) {
- brushstroke.serialize(outFile);
- }
- outFile.close();
- if (outFile.fail()) {
- MessageBox(hWnd, L"Error occurred while saving the file", L"Save Error", MB_OK | MB_ICONERROR);
- }
- else {
- isDirty = false; // Reset the dirty flag after successful save
- }
- }
- else {
- MessageBox(hWnd, L"Could not open file for saving", L"Save Error", MB_OK | MB_ICONERROR);
- }
- }
- void LoadDrawing(const string& filename) {
- ifstream inFile(filename);
- if (inFile.is_open()) {
- int numBrushstrokes;
- inFile >> numBrushstrokes;
- storedBrushstrokes.clear();
- storedBrushstrokes.reserve(numBrushstrokes);
- for (int i = 0; i < numBrushstrokes; ++i) {
- char type;
- Brushstroke brushstroke;
- inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size;
- storedBrushstrokes.push_back(brushstroke);
- }
- inFile.close();
- RedrawStrokes();
- isDirty = false; // Inserted here
- }
- }
- void SaveDrawingDialog(HWND hwnd) {
- OPENFILENAME ofn;
- wchar_t szFileName[MAX_PATH] = L"";
- ZeroMemory(&ofn, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = hwnd;
- ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
- ofn.lpstrFile = szFileName;
- ofn.nMaxFile = MAX_PATH;
- ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
- ofn.lpstrDefExt = L"txt";
- if (GetSaveFileName(&ofn)) {
- std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
- std::string filenameStr = converter.to_bytes(szFileName);
- SaveDrawing(filenameStr);
- MessageBox(hwnd, L"Save Complete", L"Doodle App", MB_OK | MB_ICONINFORMATION);
- SetWindowTitle(hwnd, szFileName);
- }
- }
- void LoadDrawingDialog(HWND hwnd) {
- OPENFILENAME ofn;
- wchar_t szFileName[MAX_PATH] = L"";
- ZeroMemory(&ofn, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = hwnd;
- ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
- ofn.lpstrFile = szFileName;
- ofn.nMaxFile = MAX_PATH;
- ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
- if (GetOpenFileName(&ofn)) {
- std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
- std::string filenameStr = converter.to_bytes(szFileName);
- LoadDrawing(filenameStr);
- SetWindowTitle(hwnd, szFileName);
- }
- }
- void SanitizeAndSaveDrawing(const string& filename) {
- ofstream outFile(filename);
- if (outFile.is_open()) {
- RECT rect;
- GetClientRect(hWnd, &rect);
- vector<Brushstroke> validBrushstrokes;
- for (const auto& brushstroke : storedBrushstrokes) {
- if (IsPointInClientRect(hWnd, brushstroke.x, brushstroke.y)) {
- validBrushstrokes.push_back(brushstroke);
- }
- }
- outFile << validBrushstrokes.size() << endl;
- for (const auto& brushstroke : validBrushstrokes) {
- brushstroke.serialize(outFile);
- }
- outFile.close();
- }
- }
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- switch (uMsg) {
- case WM_CREATE:
- {
- hWnd = hwnd;
- ShowWindow(hwnd, SW_MAXIMIZE);
- RECT rect;
- GetClientRect(hwnd, &rect);
- HDC hdc = GetDC(hwnd);
- memDC = CreateCompatibleDC(hdc);
- memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
- SelectObject(memDC, memBitmap);
- SetBkMode(memDC, TRANSPARENT);
- FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
- ReleaseDC(hwnd, hdc);
- //SaveDrawing("drawing.txt");
- CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
- std::wstring initialFileName = L"drawing.txt";
- if (pCreate && pCreate->lpCreateParams) {
- initialFileName = *reinterpret_cast<std::wstring*>(pCreate->lpCreateParams);
- }
- std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
- std::string filenameStr = converter.to_bytes(initialFileName);
- LoadDrawing(filenameStr);
- SetWindowTitle(hwnd, initialFileName);
- break;
- }
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
- memDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_LBUTTONDOWN:
- {
- isDrawing = true;
- int x = GET_X_LPARAM(lParam);
- int y = GET_Y_LPARAM(lParam);
- if (isPaintbrushSelected) {
- DrawBrush(memDC, x, y);
- storedBrushstrokes.push_back({ x, y, brushSize });
- isDirty = true;
- }
- else if (isEraserSelected) {
- Erase(memDC, x, y, brushSize);
- isDirty = true;
- }
- InvalidateRect(hwnd, NULL, FALSE);
- break;
- }
- case WM_LBUTTONUP:
- isDrawing = false;
- break;
- case WM_MOUSEMOVE:
- if (isDrawing) {
- int x = GET_X_LPARAM(lParam);
- int y = GET_Y_LPARAM(lParam);
- if (isPaintbrushSelected) {
- DrawBrush(memDC, x, y);
- storedBrushstrokes.push_back({ x, y, brushSize });
- isDirty = true;
- }
- else if (isEraserSelected) {
- Erase(memDC, x, y, brushSize);
- isDirty = true;
- }
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_KEYDOWN:
- switch (wParam) {
- case VK_ESCAPE:
- if (isDirty) {
- int result = MessageBox(hwnd, L"Do you want to save your work before exiting?", L"Save Changes", MB_YESNOCANCEL | MB_ICONQUESTION);
- if (result == IDYES) {
- // Implement save functionality here
- SaveDrawing("painting.txt");
- // After saving, set g_isModified to false
- isDirty = false;
- PostQuitMessage(0);
- }
- else if (result == IDNO) {
- PostQuitMessage(0);
- }
- // If IDCANCEL, do nothing and return to the application
- }
- else {
- PostQuitMessage(0);
- }
- return 0;
- //break;
- //case VK_ESCAPE:
- //PostQuitMessage(0);
- //return 0;
- case VK_F1:
- 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);
- return 0;
- case 'P':
- isPaintbrushSelected = true;
- isEraserSelected = false;
- break;
- case 'E':
- isEraserSelected = true;
- isPaintbrushSelected = false;
- break;
- case 'C':
- isClearing = true;
- ClearDrawing(hwnd);
- isClearing = false;
- isDirty = true;
- break;
- case VK_OEM_PLUS:
- brushSize += 2;
- break;
- case VK_OEM_MINUS:
- brushSize = max(1, brushSize - 2);
- break;
- case 'S':
- if (GetKeyState(VK_CONTROL) & 0x8000) {
- SaveDrawingDialog(hwnd);
- }
- break;
- case 'O':
- if (GetKeyState(VK_CONTROL) & 0x8000) {
- LoadDrawingDialog(hwnd);
- }
- break;
- //case VK_ESCAPE:
- //SendMessage(hwnd, WM_CLOSE, 0, 0);
- //break;
- }
- break;
- case WM_SIZE:
- if (wParam == SIZE_MAXIMIZED) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- HBITMAP newBitmap = CreateCompatibleBitmap(GetDC(hwnd), rect.right - rect.left, rect.bottom - rect.top);
- SelectObject(memDC, newBitmap);
- DeleteObject(memBitmap);
- memBitmap = newBitmap;
- RedrawStrokes();
- }
- break;
- case WM_SETCURSOR:
- if (LOWORD(lParam) == HTCLIENT) {
- SetCursor(LoadCursor(NULL, IDC_ARROW));
- return TRUE;
- }
- break;
- //Remove below function (added new)
- case WM_CLOSE:
- if (isDirty) {
- int result = MessageBox(hwnd, L"Do you want to save your changes?", L"Doodle App", MB_YESNOCANCEL | MB_ICONQUESTION);
- if (result == IDYES) {
- SaveDrawing("drawing.txt");
- }
- else if (result == IDCANCEL) {
- return 0; // Don't close the window
- }
- }
- DestroyWindow(hwnd);
- break;
- //original WM_DESTROY function below
- /*if (isDirty) {
- SaveDrawing("drawing.txt");
- }
- //SetWindowTitle(hwnd, L"drawing.txt");
- PostQuitMessage(0);
- break;*/
- //Ask to Save Changes new function below
- /*if (isDirty) {
- int result = MessageBox(hwnd, L"Do you want to save your changes?", L"Doodle App", MB_YESNOCANCEL | MB_ICONQUESTION);
- if (result == IDYES) {
- SaveDrawing("drawing.txt");
- }
- else if (result == IDCANCEL) {
- return 0; // Don't close the window
- }
- }
- PostQuitMessage(0);
- break;*/
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- }
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
- hInst = hInstance;
- const wchar_t CLASS_NAME[] = L"PaintCanvas";
- WNDCLASS wc = {};
- wc.lpfnWndProc = WindowProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASS_NAME;
- wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); // Add this line
- RegisterClass(&wc);
- 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);
- if (hwnd == NULL) {
- return 0;
- }
- ShowWindow(hwnd, SW_MAXIMIZE);
- MSG msg = {};
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement