Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ==++ Here's the full source code for (file 1/1) of "main.cpp"::++==
- #define NOMINMAX
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <windef.h>
- #include <wingdi.h>
- #include <algorithm>
- #include <iostream>
- #include <vector>
- #include <cmath>
- #include <commctrl.h>
- #include <commdlg.h> // Add at the top with other includes
- //#include <msimg32.h>
- //#include <windows.h>
- #include <stdio.h>
- #include <iostream>
- #include "resource.h" // Add this with your other includes
- #pragma comment(lib, "comctl32.lib")
- #pragma comment(lib, "comdlg32.lib")
- #pragma comment(lib, "msimg32.lib")
- using namespace std;
- struct DrawPoint {
- int x, y;
- DWORD timestamp;
- DrawPoint() : x(0), y(0), timestamp(0) {} // Default constructor
- DrawPoint(int px, int py) : x(px), y(py), timestamp(GetTickCount()) {} // Two-parameter constructor
- };
- std::vector<DrawPoint> strokeBuffer;
- const int STROKE_BUFFER_SIZE = 3; // Adjust for curve smoothness
- const double MAX_SPEED = 1000.0; // Maximum pixels per second
- const double MIN_DISTANCE = 2.0; // Minimum distance between points
- // Forward Declarations
- //struct Brushstroke;
- //struct Eraserstroke;
- void DrawSmoothStroke(HDC hdc, const std::vector<DrawPoint>& points, bool isEraser);
- void DrawBrush(HDC hdc, int x, int y, bool isEraser = false, bool interpolate = true);
- //void DebugDraw(HDC hdc);
- void Erase(HDC hdc, int x, int y);
- void ClearDrawing(HWND hwnd);
- void UpdateStatus(HWND hwnd);
- //void ClearDrawing(HDC hdc, int width, int height);
- //void DrawSmoothBrush(HDC hdc, int x, int y, bool isScreenDC);
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- // Add these global variables at the top
- int virtualWidth = 8192;
- int virtualHeight = 8192;
- int scrollX = 0; // Will be initialized properly in InitializeMemoryBitmap
- int scrollY = 0; // Will be initialized properly in InitializeMemoryBitmap
- int canvasWidth = 8192;
- int canvasHeight = 8192;
- bool isSpacePressed = false;
- bool isPanning = false; // Add this new variable
- POINT lastDrawPoint = { -1, -1 };
- POINT lastMousePos = { 0, 0 };
- POINT dragStart = { 0, 0 };
- //std::vector<POINT> currentStroke; // Store points in current stroke
- // Add these global variables if not already present
- //std::vector<Brushstroke> storedBrushstrokes;
- //std::vector<Eraserstroke> storedEraserstrokes;
- HDC hMemoryDC = NULL;
- HBITMAP hMemoryBitmap = NULL;
- HBITMAP hOldBitmap = NULL; // Add this to store the old bitmap
- HINSTANCE hInst;
- //bool isPaintbrushSelected = true; // Add a global variable to track the selected tool
- // Define a vector to store the doodle points for the Paintbrush tool
- //std::vector<POINT> paintbrushDoodlePoints;
- //new mod code
- POINT previousPoint; // Add a new global variable to track the previous point
- // Declare hdc as a global variable
- HDC hdc;
- HWND hWnd; // Declare the window handle variable globally or within the appropriate scope
- //bool needsRedraw = true; // Add this line at the top of your file
- // Declare a global variable to specify the grid spacing
- //int gridSpacing = 20;
- const int GRID_SIZE = 100; // Size of each grid cell
- const COLORREF GRID_COLOR = RGB(200, 200, 220); // Lighter blue-grey
- HDC hGridDC = NULL;
- HBITMAP hGridBitmap = NULL;
- BOOL gridInitialized = FALSE;
- // Add to globals
- float gridZoomFactor = 1.0f;
- bool showGrid = true;
- bool useAlphaGrid = false; // Toggle between normal and alpha-blended grid
- int gridOpacity = 255; // 0-255
- COLORREF currentBrushColor = RGB(255, 0, 0); // Default red
- bool isInitialized = false;
- bool isPaintbrushSelected = true;;
- bool isDrawing = false;
- bool isErasing = false;
- bool isClearing = false;
- bool isEraserMode = false;
- bool isEraserSelected = false;
- int minBrushSize = 5;
- int maxBrushSize = 50;
- int brushSize = 10;
- //POINT previousPoint;
- // Define a struct to store brushstroke information
- /*struct Brushstroke {
- int x;
- int y;
- int size;
- COLORREF color;
- // Add any other necessary properties for the brushstroke
- };*/
- // Define a struct to store eraserstroke information
- /*struct Eraserstroke {
- int x;
- int y;
- int size;
- COLORREF color;
- // Add any other necessary properties for the eraserstroke
- };*/
- // Declare a vector to store the brushstrokes
- //std::vector<Brushstroke> storedBrushstrokes;
- //std::vector<Eraserstroke> storedEraserstrokes;
- // Global variables to store the minimized brushstrokes
- //std::vector<Brushstroke> minimizedDrawnBrushstrokes;
- //std::vector<Eraserstroke> minimizedErasedBrushstrokes;
- // Function declaration for DrawGrid
- //void DrawGrid(HDC hdc, int spacing, COLORREF color); //drawgrid disableddefault
- // Optimized DrawGrid function to efficiently draw both vertical and horizontal lines
- // Add this function
- /*void CleanupOldStrokes() {
- const size_t MAX_STROKES = 100000;
- if (storedBrushstrokes.size() > MAX_STROKES) {
- storedBrushstrokes.erase(storedBrushstrokes.begin(),
- storedBrushstrokes.begin() + (storedBrushstrokes.size() - MAX_STROKES));
- }
- if (storedEraserstrokes.size() > MAX_STROKES) {
- storedEraserstrokes.erase(storedEraserstrokes.begin(),
- storedEraserstrokes.begin() + (storedEraserstrokes.size() - MAX_STROKES));
- }
- }*/
- //new gpt broken?
- /*void DrawBrush(HDC hdc, int x, int y) {
- // Debug output
- char debug[256];
- sprintf_s(debug, "DrawBrush called at: x=%d, y=%d\n", x, y);
- OutputDebugStringA(debug);
- HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
- HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
- if (!redBrush || !redPen) {
- OutputDebugStringA("Failed to create brush or pen\n");
- return;
- }
- HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, redBrush);
- HPEN oldPen = (HPEN)SelectObject(hdc, redPen);
- if (!oldBrush || !oldPen) {
- OutputDebugStringA("Failed to select brush or pen\n");
- DeleteObject(redBrush);
- DeleteObject(redPen);
- return;
- }
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- SelectObject(hdc, oldBrush);
- SelectObject(hdc, oldPen);
- DeleteObject(redBrush);
- DeleteObject(redPen);
- }*/
- // Add this function to initialize the memory bitmap
- // Add this function
- // Modify InitializeMemoryBitmap:
- void InitializeMemoryBitmap(HWND hwnd) {
- HDC hdc = GetDC(hwnd);
- if (!hdc) {
- return;
- }
- hMemoryDC = CreateCompatibleDC(hdc);
- if (!hMemoryDC) {
- ReleaseDC(hwnd, hdc);
- return;
- }
- hMemoryBitmap = CreateCompatibleBitmap(hdc, virtualWidth, virtualHeight);
- if (!hMemoryBitmap) {
- DeleteDC(hMemoryDC);
- ReleaseDC(hwnd, hdc);
- return;
- }
- hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hMemoryBitmap);
- // Fill with white background
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- RECT rect = { 0, 0, virtualWidth, virtualHeight };
- FillRect(hMemoryDC, &rect, whiteBrush);
- DeleteObject(whiteBrush);
- ReleaseDC(hwnd, hdc);
- isInitialized = true;
- // Draw coordinate guides
- HPEN guidePen = CreatePen(PS_SOLID, 1, RGB(200, 200, 200));
- SelectObject(hMemoryDC, guidePen);
- // Draw center lines
- MoveToEx(hMemoryDC, virtualWidth / 2, 0, NULL);
- LineTo(hMemoryDC, virtualWidth / 2, virtualHeight);
- MoveToEx(hMemoryDC, 0, virtualHeight / 2, NULL);
- LineTo(hMemoryDC, virtualWidth, virtualHeight / 2);
- // Draw border
- HPEN edgePen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
- SelectObject(hMemoryDC, edgePen);
- Rectangle(hMemoryDC, 0, 0, virtualWidth - 1, virtualHeight - 1);
- DeleteObject(guidePen);
- DeleteObject(edgePen);
- // Initialize scroll position to center the canvas
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- scrollX = (virtualWidth - clientRect.right) / 2;
- scrollY = (virtualHeight - clientRect.bottom) / 2;
- }
- // Initialize scroll position to center the canvas
- //RECT clientRect;
- //GetClientRect(hwnd, &clientRect);
- //scrollX = -virtualWidth / 2 + (clientRect.right / 2);
- //scrollY = -virtualHeight / 2 + (clientRect.bottom / 2);
- //}
- void DrawSmoothStroke(HDC hdc, const std::vector<DrawPoint>& points, bool isEraser) {
- if (points.size() < 2) return;
- COLORREF color = isEraser ? RGB(255, 255, 255) : currentBrushColor;
- HBRUSH brush = CreateSolidBrush(color);
- HPEN pen = CreatePen(PS_SOLID, 1, color);
- HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, brush);
- HPEN oldPen = (HPEN)SelectObject(hdc, pen);
- // Draw first point
- Ellipse(hdc,
- points[0].x - brushSize,
- points[0].y - brushSize,
- points[0].x + brushSize,
- points[0].y + brushSize);
- // Draw smooth line between points
- for (size_t i = 1; i < points.size(); ++i) {
- const DrawPoint& prev = points[i - 1];
- const DrawPoint& curr = points[i];
- double dx = curr.x - prev.x;
- double dy = curr.y - prev.y;
- double distance = sqrt(dx * dx + dy * dy);
- if (distance > 0) {
- int steps = (int)(distance / (brushSize * 0.3)); // Adjust density
- steps = min(max(steps, 1), 15); // Limit steps
- for (int step = 0; step <= steps; ++step) {
- double t = step / (double)steps;
- int x = (int)(prev.x + dx * t);
- int y = (int)(prev.y + dy * t);
- // Draw interpolated point
- Ellipse(hdc,
- x - brushSize,
- y - brushSize,
- x + brushSize,
- y + brushSize);
- }
- }
- }
- SelectObject(hdc, oldBrush);
- SelectObject(hdc, oldPen);
- DeleteObject(brush);
- DeleteObject(pen);
- }
- // Replace your DrawBrush function with this simpler version:
- // Modify DrawBrush function to use currentBrushColor
- void DrawBrush(HDC hdc, int x, int y, bool isEraser, bool interpolate) {
- if (x < 0 || x > virtualWidth || y < 0 || y > virtualHeight) {
- return;
- }
- COLORREF color = isEraser ? RGB(255, 255, 255) : currentBrushColor;
- HBRUSH brush = CreateSolidBrush(color);
- HPEN pen = CreatePen(PS_SOLID, 1, color);
- HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, brush);
- HPEN oldPen = (HPEN)SelectObject(hdc, pen);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- SelectObject(hdc, oldBrush);
- SelectObject(hdc, oldPen);
- DeleteObject(brush);
- DeleteObject(pen);
- }
- // Optional: Add these helper functions for better stroke management
- void StartStroke(int x, int y) {
- strokeBuffer.clear();
- strokeBuffer.push_back(DrawPoint(x, y));
- }
- void AddToStroke(int x, int y) {
- if (strokeBuffer.empty()) {
- StartStroke(x, y);
- return;
- }
- const DrawPoint& lastPt = strokeBuffer.back();
- double dx = x - lastPt.x;
- double dy = y - lastPt.y;
- double distance = sqrt(dx * dx + dy * dy);
- if (distance >= MIN_DISTANCE) {
- strokeBuffer.push_back(DrawPoint(x, y));
- while (strokeBuffer.size() > STROKE_BUFFER_SIZE) {
- strokeBuffer.erase(strokeBuffer.begin());
- }
- }
- }
- void EndStroke() {
- strokeBuffer.clear();
- }
- // Add this function to show color dialog
- void ShowColorPicker(HWND hwnd) {
- CHOOSECOLOR cc = { sizeof(CHOOSECOLOR) };
- static COLORREF customColors[16] = { 0 };
- cc.hwndOwner = hwnd;
- cc.rgbResult = currentBrushColor;
- cc.lpCustColors = customColors;
- cc.Flags = CC_FULLOPEN | CC_RGBINIT;
- if (ChooseColor(&cc)) {
- currentBrushColor = cc.rgbResult;
- UpdateStatus(hwnd); // Update status bar to show new color
- }
- }
- //old pre-gpt
- /*void DrawBrush(HDC hdc, int x, int y) {
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0)); // Set the brush color to fully red
- SelectObject(hdc, GetStockObject(NULL_PEN)); // Set the pen to null to remove the border
- SelectObject(hdc, hBrush);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- DeleteObject(hBrush);
- }*/
- // Add this debug function
- /*void DebugDraw(HDC hdc) {
- HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
- RECT testRect = { 100, 100, 200, 200 };
- FillRect(hdc, &testRect, redBrush);
- DeleteObject(redBrush);
- }*/
- /*void DrawBrush(HDC hdc, int x, int y) {
- HRGN hRgn = CreateEllipticRgn(x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- FillRgn(hdc, hRgn, CreateSolidBrush(RGB(255, 0, 0)));
- DeleteObject(hRgn);
- }*/
- //broken old
- void Erase(HDC hdc, int x, int y) {
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, GetStockObject(NULL_PEN));
- SelectObject(hdc, hBrush);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- DeleteObject(hBrush);
- }
- /*void Erase(HDC hdc, int x, int y) {
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); // Set the brush color to white
- HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- SelectObject(hdc, hOldBrush);
- DeleteObject(hBrush);
- }*/
- //start test of new eraser
- /*void Erase(HDC hdc, int x, int y) {
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, GetStockObject(NULL_PEN));
- SelectObject(hdc, hBrush);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- DeleteObject(hBrush);
- }*/
- //end test of new eraser
- //start commented out testing new gpt function eraser
- /*void Erase(HDC hdc, int x, int y) {
- // HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); // Set the brush color to white
- // HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0)); // Set the brush color to black
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); // Set the brush color to white
- HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255)); // Set the pen color to white
- HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);
- HGDIOBJ hOldPen = SelectObject(hdc, hPen);
- Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
- SelectObject(hdc, hOldBrush);
- SelectObject(hdc, hOldPen);
- DeleteObject(hBrush);
- DeleteObject(hPen);
- }*/
- //end commented out testing new gpt function eraser
- void ClearCanvas(HWND hwnd) {
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- RECT rect = { 0, 0, virtualWidth, virtualHeight };
- FillRect(hMemoryDC, &rect, whiteBrush);
- DeleteObject(whiteBrush);
- InvalidateRect(hwnd, NULL, FALSE);
- }
- void ClearDrawing(HWND hwnd) {
- // Clear the canvas
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- RECT rect = { 0, 0, virtualWidth, virtualHeight };
- FillRect(hMemoryDC, &rect, whiteBrush);
- DeleteObject(whiteBrush);
- // Reset scroll position to center
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- scrollX = (virtualWidth - clientRect.right) / 2;
- scrollY = (virtualHeight - clientRect.bottom) / 2;
- // Redraw coordinate guides and border
- // Draw coordinate guides
- HPEN guidePen = CreatePen(PS_SOLID, 1, RGB(200, 200, 200));
- SelectObject(hMemoryDC, guidePen);
- // Draw center lines
- MoveToEx(hMemoryDC, virtualWidth / 2, 0, NULL);
- LineTo(hMemoryDC, virtualWidth / 2, virtualHeight);
- MoveToEx(hMemoryDC, 0, virtualHeight / 2, NULL);
- LineTo(hMemoryDC, virtualWidth, virtualHeight / 2);
- // Draw border
- HPEN edgePen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
- SelectObject(hMemoryDC, edgePen);
- Rectangle(hMemoryDC, 0, 0, virtualWidth - 1, virtualHeight - 1);
- DeleteObject(guidePen);
- DeleteObject(edgePen);
- // Force redraw
- InvalidateRect(hwnd, NULL, FALSE);
- }
- // Add this function
- void InitializeGridCache(HDC hdc) {
- if (hGridDC) {
- DeleteDC(hGridDC);
- DeleteObject(hGridBitmap);
- }
- int scaledGridSize = (int)(GRID_SIZE * gridZoomFactor);
- hGridDC = CreateCompatibleDC(hdc);
- hGridBitmap = CreateCompatibleBitmap(hdc, scaledGridSize, scaledGridSize);
- HBITMAP oldBitmap = (HBITMAP)SelectObject(hGridDC, hGridBitmap);
- // Fill with white background
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- RECT rect = { 0, 0, scaledGridSize, scaledGridSize };
- FillRect(hGridDC, &rect, whiteBrush);
- DeleteObject(whiteBrush);
- // Draw grid lines
- HPEN gridPen = CreatePen(PS_SOLID, 1, GRID_COLOR);
- HPEN oldPen = (HPEN)SelectObject(hGridDC, gridPen);
- // Draw right and bottom lines of the cell
- MoveToEx(hGridDC, scaledGridSize - 1, 0, NULL);
- LineTo(hGridDC, scaledGridSize - 1, scaledGridSize);
- MoveToEx(hGridDC, 0, scaledGridSize - 1, NULL);
- LineTo(hGridDC, scaledGridSize, scaledGridSize - 1);
- SelectObject(hGridDC, oldPen);
- DeleteObject(gridPen);
- gridInitialized = TRUE;
- }
- // Add this function to draw the grid
- // Modified DrawGrid function using cached grid cell
- void DrawGrid(HDC hdc, const RECT& clientRect, int scrollX, int scrollY) {
- // Set up DC for better line quality
- SetBkMode(hdc, TRANSPARENT);
- HPEN gridPen = CreatePen(PS_SOLID, 1, GRID_COLOR);
- HPEN oldPen = (HPEN)SelectObject(hdc, gridPen);
- int scaledGridSize = (int)(GRID_SIZE * gridZoomFactor);
- // Calculate grid offset
- int offsetX = -(scrollX % scaledGridSize);
- int offsetY = -(scrollY % scaledGridSize);
- // Draw vertical lines
- for (int x = offsetX; x <= clientRect.right; x += scaledGridSize) {
- MoveToEx(hdc, x, 0, NULL);
- LineTo(hdc, x, clientRect.bottom);
- }
- // Draw horizontal lines
- for (int y = offsetY; y <= clientRect.bottom; y += scaledGridSize) {
- MoveToEx(hdc, 0, y, NULL);
- LineTo(hdc, clientRect.right, y);
- }
- // Clean up
- SelectObject(hdc, oldPen);
- DeleteObject(gridPen);
- }
- void DrawGridWithAlpha(HDC hdc, const RECT& clientRect, int scrollX, int scrollY) {
- HDC tempDC = CreateCompatibleDC(hdc);
- HBITMAP tempBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);
- HBITMAP oldTempBitmap = (HBITMAP)SelectObject(tempDC, tempBitmap);
- // Fill with white background
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(tempDC, &clientRect, whiteBrush);
- DeleteObject(whiteBrush);
- // Draw grid on temporary DC
- SetBkMode(tempDC, TRANSPARENT);
- HPEN gridPen = CreatePen(PS_SOLID, 1, GRID_COLOR);
- HPEN oldPen = (HPEN)SelectObject(tempDC, gridPen);
- int scaledGridSize = (int)(GRID_SIZE * gridZoomFactor);
- int offsetX = -(scrollX % scaledGridSize);
- int offsetY = -(scrollY % scaledGridSize);
- // Draw vertical lines
- for (int x = offsetX; x <= clientRect.right; x += scaledGridSize) {
- MoveToEx(tempDC, x, 0, NULL);
- LineTo(tempDC, x, clientRect.bottom);
- }
- // Draw horizontal lines
- for (int y = offsetY; y <= clientRect.bottom; y += scaledGridSize) {
- MoveToEx(tempDC, 0, y, NULL);
- LineTo(tempDC, clientRect.right, y);
- }
- SelectObject(tempDC, oldPen);
- DeleteObject(gridPen);
- // Blend the grid
- BLENDFUNCTION bf;
- bf.BlendOp = AC_SRC_OVER;
- bf.BlendFlags = 0;
- bf.SourceConstantAlpha = gridOpacity;
- bf.AlphaFormat = 0;
- AlphaBlend(hdc, 0, 0, clientRect.right, clientRect.bottom,
- tempDC, 0, 0, clientRect.right, clientRect.bottom,
- bf);
- // Cleanup
- SelectObject(tempDC, oldTempBitmap);
- DeleteObject(tempBitmap);
- DeleteDC(tempDC);
- }
- //newgptdelete
- /*void ClearDrawing(HWND hwnd) {
- RECT rect = { 0, 0, virtualWidth, virtualHeight };
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(hMemoryDC, &rect, whiteBrush);
- DeleteObject(whiteBrush);
- scrollX = -virtualWidth / 2; // Reset to center
- scrollY = -virtualHeight / 2; // Reset to center
- InvalidateRect(hwnd, NULL, FALSE);
- }*/
- /*void ClearDrawing(HDC hdc, int width, int height) {
- RECT rect = { 0, 0, width, height };
- // HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); // Set the color to white
- // HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0)); // Set the color to black
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); // Set the color to white
- FillRect(hdc, &rect, hBrush);
- DeleteObject(hBrush);
- }*/
- //removing drawgrid
- /*void DrawGrid(HDC hdc, int spacing, COLORREF color) {
- RECT rect;
- GetClientRect(hWnd, &rect);
- HPEN hPen = CreatePen(PS_SOLID, 1, color);
- HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
- // Draw vertical lines
- for (int x = 0; x <= rect.right; x += spacing) {
- MoveToEx(hdc, x, 0, NULL);
- LineTo(hdc, x, rect.bottom);
- }
- // Draw horizontal lines
- for (int y = 0; y <= rect.bottom; y += spacing) {
- MoveToEx(hdc, 0, y, NULL);
- LineTo(hdc, rect.right, y);
- }
- SelectObject(hdc, hOldPen);
- DeleteObject(hPen);
- }*/
- //gpts old drawgrid
- /*void DrawGrid(HDC hdc, int spacing, COLORREF color) {
- RECT rect;
- GetClientRect(hWnd, &rect);
- HPEN hPen = CreatePen(PS_SOLID, 1, color);
- HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
- // Draw vertical lines
- for (int x = 0; x < rect.right; x += spacing) {
- MoveToEx(hdc, x, 0, NULL);
- LineTo(hdc, x, rect.bottom);
- }
- // Draw horizontal lines
- for (int y = 0; y < rect.bottom; y += spacing) {
- MoveToEx(hdc, 0, y, NULL);
- LineTo(hdc, rect.right, y);
- }
- SelectObject(hdc, hOldPen);
- DeleteObject(hPen);
- }*/
- //chatgpt disabled
- /*void DrawGrid(HDC hdc, int spacing, COLORREF color) {
- RECT rect;
- GetClientRect(hWnd, &rect);
- HPEN hPen = CreatePen(PS_SOLID, 1, color);
- HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
- // Draw vertical lines
- for (int x = 0; x < rect.right; x += spacing) {
- MoveToEx(hdc, x, 0, NULL);
- LineTo(hdc, x, rect.bottom);
- }
- // Draw horizontal lines
- for (int y = 0; y < rect.bottom; y += spacing) {
- MoveToEx(hdc, 0, y, NULL);
- LineTo(hdc, rect.right, y);
- }
- SelectObject(hdc, hOldPen);
- DeleteObject(hPen);
- }*/
- //temp disabled for relocated code
- /*int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
- const wchar_t CLASS_NAME[] = L"DoodleAppClass";
- WNDCLASS wc = { };
- wc.lpfnWndProc = WindowProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASS_NAME;
- RegisterClass(&wc);
- hInst = hInstance;
- HWND hwnd = CreateWindowEx(
- 0,
- CLASS_NAME,
- L"Doodle App",
- WS_OVERLAPPEDWINDOW | WS_MAXIMIZE, //& ~WS_MINIMIZEBOX, Add WS_MAXIMIZE style
- // Disable the Minimize button
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL
- );
- //hdc = GetDC(hWnd); //gptadded
- if (hwnd == NULL) {
- return 0;
- }
- ShowWindow(hwnd, SW_SHOWMAXIMIZED); // Show the window maximized
- //old code
- //ShowWindow(hwnd, nCmdShow);
- MSG msg = { };
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }*/
- //new code
- /*void DrawSmoothBrush(HDC hdc, int x, int y) {
- if (!isDrawing) return;
- int currentX = x + scrollX;
- int currentY = y + scrollY;
- int prevX = previousPoint.x + scrollX;
- int prevY = previousPoint.y + scrollY;
- // Draw line between points for smoothness
- int numPoints = 10;
- for (int i = 0; i <= numPoints; i++) {
- float t = (float)i / numPoints;
- int drawX = prevX + (int)(t * (currentX - prevX));
- int drawY = prevY + (int)(t * (currentY - prevY));
- if (isPaintbrushSelected) {
- DrawBrush(hdc, drawX, drawY);
- }
- else if (isEraserSelected) {
- Erase(hdc, drawX, drawY);
- }
- }
- previousPoint.x = x;
- previousPoint.y = y;
- }*/
- // Update status text when tool changes:
- // Modify UpdateStatus to show current color
- void UpdateStatus(HWND hwnd) {
- HWND hStatus = GetDlgItem(hwnd, 0);
- if (hStatus) {
- wchar_t status[512];
- BYTE r = GetRValue(currentBrushColor);
- BYTE g = GetGValue(currentBrushColor);
- BYTE b = GetBValue(currentBrushColor);
- // Show canvas center position instead of mouse position
- int centerX = scrollX + (virtualWidth / 2);
- int centerY = scrollY + (virtualHeight / 2);
- swprintf_s(status,
- L"Mode: %s | Brush: %d | Color: RGB(%d,%d,%d) | Grid: %s%s | Zoom: %.1fx | Opacity: %d%% | Canvas Pos: (%d,%d)",
- isEraserMode ? L"Eraser" : L"Draw",
- brushSize,
- r, g, b,
- showGrid ? L"On" : L"Off",
- useAlphaGrid ? L"(Alpha)" : L"",
- gridZoomFactor,
- (gridOpacity * 100) / 255,
- centerX, centerY
- );
- SetWindowText(hStatus, status);
- }
- }
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- switch (uMsg) {
- case WM_CREATE:
- {
- InitializeMemoryBitmap(hwnd);
- if (hMemoryDC) {
- HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
- RECT testRect = { 100, 100, 200, 200 };
- FillRect(hMemoryDC, &testRect, redBrush);
- DeleteObject(redBrush);
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else {
- MessageBox(hwnd, L"Memory DC failed to initialize", L"Error", MB_OK);
- }
- UpdateStatus(hwnd); // Initial status update
- return 0;
- }
- case WM_KEYDOWN:
- {
- if (wParam == VK_SPACE && !isSpacePressed) {
- isSpacePressed = true;
- GetCursorPos(&lastMousePos);
- ScreenToClient(hwnd, &lastMousePos);
- SetCursor(LoadCursor(NULL, IDC_SIZEALL));
- SetCapture(hwnd); // Capture mouse when space is pressed
- return 0;
- }
- else if (wParam == 0x50) { // 'P' key
- isPaintbrushSelected = true;
- isEraserMode = false;
- UpdateStatus(hwnd);
- }
- else if (wParam == 0x45) { // 'E' key
- isPaintbrushSelected = false;
- isEraserMode = true;
- UpdateStatus(hwnd);
- }
- else if (wParam == 'Q') { // 'Q' key for color picker
- ShowColorPicker(hwnd);
- }
- else if (wParam == VK_ADD || wParam == VK_OEM_PLUS) {
- brushSize = std::min(50, brushSize + 5);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_SUBTRACT || wParam == VK_OEM_MINUS) {
- brushSize = std::max(5, brushSize - 5);
- UpdateStatus(hwnd);
- }
- else if (wParam == 0x43) { // 'C' key
- if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
- ClearDrawing(hwnd);
- }
- }
- else if (wParam == VK_HOME) {
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- // Calculate the center position
- scrollX = (virtualWidth - clientRect.right) / 2;
- scrollY = (virtualHeight - clientRect.bottom) / 2;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == 'G') { // Toggle grid visibility
- showGrid = !showGrid;
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == 'A') { // Toggle alpha grid
- useAlphaGrid = !useAlphaGrid;
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_OEM_PLUS && (GetKeyState(VK_CONTROL) & 0x8000)) { // Ctrl + Plus
- gridZoomFactor *= 1.1f;
- gridInitialized = FALSE; // Force grid cache rebuild
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_OEM_MINUS && (GetKeyState(VK_CONTROL) & 0x8000)) { // Ctrl + Minus
- gridZoomFactor *= 0.9f;
- if (gridZoomFactor < 0.1f) gridZoomFactor = 0.1f;
- gridInitialized = FALSE; // Force grid cache rebuild
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_OEM_6 && useAlphaGrid) { // ']' key - increase opacity
- gridOpacity = min(255, gridOpacity + 15);
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_OEM_4 && useAlphaGrid) { // '[' key - decrease opacity
- gridOpacity = max(0, gridOpacity - 15);
- InvalidateRect(hwnd, NULL, FALSE);
- UpdateStatus(hwnd);
- }
- else if (wParam == VK_ESCAPE) {
- PostQuitMessage(0);
- return 0;
- }
- else if (wParam == VK_F1) {
- MessageBox(hwnd, TEXT("I made an Infinite Canvas app using GDI and Memory DC, no need for bloated Godot Engine/ Frameworks or M$ Infinite Canvas Control! Eternity of effort paid off! (1308 lines of code) by Entisoft Software (c) Evans Thorpemorton"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
- }
- return 0;
- }
- case WM_KEYUP:
- {
- if (wParam == VK_SPACE) {
- isSpacePressed = false;
- SetCursor(LoadCursor(NULL, IDC_ARROW));
- ReleaseCapture(); // Release mouse capture when space is released
- return 0;
- }
- }
- //break;
- // Update WM_LBUTTONDOWN handler:
- case WM_LBUTTONDOWN:
- {
- if (!isSpacePressed) {
- isDrawing = true;
- SetCapture(hwnd);
- int x = LOWORD(lParam);
- int y = HIWORD(lParam);
- int canvasX = x + scrollX;
- int canvasY = y + scrollY;
- if (canvasX >= 0 && canvasX <= virtualWidth &&
- canvasY >= 0 && canvasY <= virtualHeight) {
- StartStroke(canvasX, canvasY);
- DrawBrush(hMemoryDC, canvasX, canvasY, isEraserMode, false);
- HDC screenDC = GetDC(hwnd);
- DrawBrush(screenDC, x, y, isEraserMode, false);
- ReleaseDC(hwnd, screenDC);
- }
- }
- return 0;
- }
- //break;
- // Optional: Add this to WM_LBUTTONUP to ensure smooth lines start fresh:
- case WM_LBUTTONUP:
- {
- if (isPanning) {
- isPanning = false;
- ReleaseCapture();
- }
- if (isDrawing) {
- isDrawing = false;
- EndStroke();
- ReleaseCapture();
- }
- return 0;
- }
- //break;
- //new code
- // Modified WM_MOUSEMOVE handler:
- // Modify the WM_MOUSEMOVE handler:
- // Modify the WM_MOUSEMOVE case in WindowProc:
- case WM_MOUSEMOVE:
- {
- int x = LOWORD(lParam);
- int y = HIWORD(lParam);
- // Update status bar with current coordinates
- UpdateStatus(hwnd); // Add this line
- if (isSpacePressed) { // Removed the left click check
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- int deltaX = x - lastMousePos.x;
- int deltaY = y - lastMousePos.y;
- scrollX = std::max(0, std::min<int>(virtualWidth - clientRect.right, scrollX - deltaX));
- scrollY = std::max(0, std::min<int>(virtualHeight - clientRect.bottom, scrollY - deltaY));
- lastMousePos.x = x;
- lastMousePos.y = y;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (isDrawing && (wParam & MK_LBUTTON)) {
- int canvasX = x + scrollX;
- int canvasY = y + scrollY;
- if (canvasX >= 0 && canvasX <= virtualWidth &&
- canvasY >= 0 && canvasY <= virtualHeight) {
- AddToStroke(canvasX, canvasY);
- DrawSmoothStroke(hMemoryDC, strokeBuffer, isEraserMode);
- HDC screenDC = GetDC(hwnd);
- std::vector<DrawPoint> screenPoints;
- for (const auto& pt : strokeBuffer) {
- screenPoints.push_back(DrawPoint(pt.x - scrollX, pt.y - scrollY));
- }
- DrawSmoothStroke(screenDC, screenPoints, isEraserMode);
- ReleaseDC(hwnd, screenDC);
- }
- }
- UpdateStatus(hwnd);
- return 0;
- }
- //break;
- /* case WM_MOUSEMOVE:
- if (isDrawing) {
- HDC hdc = GetDC(hwnd);
- DrawBrush(hdc, LOWORD(lParam), HIWORD(lParam));
- ReleaseDC(hwnd, hdc);
- }
- else if (isErasing) {
- HDC hdc = GetDC(hwnd);
- Erase(hdc, LOWORD(lParam), HIWORD(lParam));
- ReleaseDC(hwnd, hdc);
- }
- else if (isClearing) {
- HDC hdc = GetDC(hwnd);
- RECT rect;
- GetClientRect(hwnd, &rect);
- ClearDrawing(hdc, rect.right, rect.bottom);
- ReleaseDC(hwnd, hdc);
- isClearing = false;
- }
- break;
- */
- case WM_SIZE:
- {
- // Handle status bar
- HWND hStatus = GetDlgItem(hwnd, 0);
- if (hStatus) {
- SendMessage(hStatus, WM_SIZE, 0, 0);
- UpdateStatus(hwnd); // Update after resize
- }
- // Handle window size changes
- if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) {
- InvalidateRect(hwnd, NULL, TRUE);
- }
- return 0;
- }
- //LASTCLASS::
- /*if (wParam == SIZE_MINIMIZED) {
- minimizedDrawnBrushstrokes = storedBrushstrokes;
- minimizedErasedBrushstrokes = storedEraserstrokes;
- }
- else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) {
- storedBrushstrokes = minimizedDrawnBrushstrokes;
- storedEraserstrokes = minimizedErasedBrushstrokes;
- // Redraw the window
- InvalidateRect(hwnd, NULL, TRUE);
- }*/
- //gonnareplace winner!
- /*if (wParam == SIZE_MINIMIZED) {
- minimizedDrawnBrushstrokes = storedBrushstrokes;
- minimizedErasedBrushstrokes = storedEraserstrokes;
- }
- else if (wParam == SIZE_RESTORED) {
- storedBrushstrokes = minimizedDrawnBrushstrokes;
- storedEraserstrokes = minimizedErasedBrushstrokes;
- InvalidateRect(hwnd, NULL, TRUE);
- }*/
- //start chatgpt new modified code
- /*if (wParam == SIZE_MINIMIZED) {
- // Save the drawn and erased brushstrokes when minimizing
- minimizedDrawnBrushstrokes = storedBrushstrokes;
- minimizedErasedBrushstrokes = storedEraserstrokes;
- }
- else if (wParam == SIZE_RESTORED) {
- // Restore the minimized brushstrokes when restoring
- storedBrushstrokes = minimizedDrawnBrushstrokes;
- storedEraserstrokes = minimizedErasedBrushstrokes;
- // Trigger a repaint to redraw the brushstrokes
- InvalidateRect(hwnd, NULL, TRUE);
- }*/
- //end chatgpt new modified code
- //start working but no erase history code (adding brushstruct for eraser logic) fallbackcode
- /*if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- //ClearDrawing(hdc, rect.right, rect.bottom);
- }*/
- //end working but no erase history code fallbackcode
- //new replaced chatgpt
- /*if (wParam == SIZE_MAXIMIZED) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- ClearDrawing(hdc, rect.right, rect.bottom);
- }*/
- /*else if (wParam == SIZE_RESTORED) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- if (isPaintbrushSelected) {
- // Redraw the stored doodle contents for the Paintbrush tool
- for (const auto& point : paintbrushDoodlePoints) {
- // Use the stored points to redraw the doodle contents for the Paintbrush tool
- // Example: Draw a small circle at each point
- Ellipse(hdc, point.x - 2, point.y - 2, point.x + 2, point.y + 2);
- }
- }
- }*/
- //old code
- //new replaced chatgpt
- /*else if (wParam == SIZE_RESTORED) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- // Handle resizing of contents when the window is restored
- // Add code to restore doodle contents here
- }
- else if (wParam == SIZE_MINIMIZED) {
- // Handle content when the window is minimized
- }*/
- //}
- //break;
- // Modified WM_PAINT handler:
- // Modify WM_PAINT to handle the centered view
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- int windowWidth = clientRect.right - clientRect.left;
- int windowHeight = clientRect.bottom - clientRect.top;
- HDC memDC = CreateCompatibleDC(hdc);
- HBITMAP memBitmap = CreateCompatibleBitmap(hdc, windowWidth, windowHeight);
- HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
- // Fill with white background
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(memDC, &clientRect, whiteBrush);
- DeleteObject(whiteBrush);
- // Draw canvas content first
- BitBlt(memDC, 0, 0, windowWidth, windowHeight,
- hMemoryDC, scrollX, scrollY, SRCCOPY);
- // Draw grid on top if enabled
- if (showGrid) {
- if (useAlphaGrid) {
- DrawGridWithAlpha(memDC, clientRect, scrollX, scrollY);
- }
- else {
- DrawGrid(memDC, clientRect, scrollX, scrollY);
- }
- }
- // Final blit to screen
- BitBlt(hdc, 0, 0, windowWidth, windowHeight,
- memDC, 0, 0, SRCCOPY);
- SelectObject(memDC, oldBitmap);
- DeleteObject(memBitmap);
- DeleteDC(memDC);
- EndPaint(hwnd, &ps);
- return 0;
- }
- // added newly to set Normal Pointer & not Busy Pointer
- case WM_SETCURSOR:
- {
- if (LOWORD(lParam) == HTCLIENT) { // Only in client area
- if (isSpacePressed) {
- SetCursor(LoadCursor(NULL, IDC_SIZEALL));
- return TRUE;
- }
- else if (isPaintbrushSelected || isEraserMode) {
- SetCursor(LoadCursor(NULL, IDC_CROSS));
- return TRUE;
- }
- }
- return DefWindowProc(hwnd, uMsg, wParam, lParam); // Use default cursor for non-client area
- }
- // In your mouse wheel handler or zoom control
- case WM_MOUSEWHEEL:
- {
- int delta = GET_WHEEL_DELTA_WPARAM(wParam);
- if (GetKeyState(VK_CONTROL) & 0x8000) {
- if (delta > 0)
- gridZoomFactor *= 1.1f;
- else
- gridZoomFactor *= 0.9f;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- return 0;
- }
- case WM_DESTROY:
- {
- if (hGridDC) {
- DeleteDC(hGridDC);
- hGridDC = NULL;
- }
- if (hGridBitmap) {
- DeleteObject(hGridBitmap);
- hGridBitmap = NULL;
- }
- if (hMemoryDC) {
- if (hOldBitmap) {
- SelectObject(hMemoryDC, hOldBitmap);
- hOldBitmap = NULL;
- }
- DeleteDC(hMemoryDC);
- hMemoryDC = NULL;
- }
- if (hMemoryBitmap) {
- DeleteObject(hMemoryBitmap);
- hMemoryBitmap = NULL;
- }
- PostQuitMessage(0);
- return 0;
- }
- default:
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- return 0;
- }
- // Add this before WinMain
- INITCOMMONCONTROLSEX icex;
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
- // Initialize Common Controls
- icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
- icex.dwICC = ICC_BAR_CLASSES;
- InitCommonControlsEx(&icex);
- const wchar_t CLASS_NAME[] = L"DoodleAppClass";
- WNDCLASS wc = { };
- wc.lpfnWndProc = WindowProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASS_NAME;
- wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); // Add this line
- RegisterClass(&wc);
- hInst = hInstance;
- // In WinMain, modify CreateWindowEx:
- HWND hwnd = CreateWindowEx(
- 0, // No extra styles needed
- CLASS_NAME,
- L"Infinite Canvas Doodle App (P=Brush E=Eraser C=Clear +-=BrushSize Space+Drag=Scroll Home=Center Q=Color G=Grid A=Alpha F1=About)",
- WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL
- );
- // Enable double buffering using SetWindowLong
- SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_COMPOSITED);
- //hdc = GetDC(hwnd);
- if (hwnd == NULL) {
- return 0;
- }
- // Add to WinMain after creating main window
- HWND hStatus = CreateWindowEx(
- 0,
- STATUSCLASSNAME,
- NULL,
- WS_CHILD | WS_VISIBLE,
- 0, 0, 0, 0,
- hwnd,
- NULL,
- hInstance,
- NULL
- );
- // Initial status update
- UpdateStatus(hwnd);
- ShowWindow(hwnd, SW_SHOWMAXIMIZED);
- //start chatgpt new modified code
- /*MSG msg = {};
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- if (msg.message == WM_SIZE) {
- if (msg.wParam == SIZE_MINIMIZED) {
- // Save the drawn and erased brushstrokes when minimizing
- std::vector<Brushstroke> minimizedDrawnBrushstrokes = storedBrushstrokes;
- std::vector<Eraserstroke> minimizedErasedBrushstrokes = storedEraserStrokes;
- }
- else if (msg.wParam == SIZE_RESTORED) {
- // Restore the minimized brushstrokes when restoring
- storedBrushstrokes = minimizedDrawnBrushstrokes;
- storedEraserStrokes = minimizedErasedBrushstrokes;
- // Trigger a repaint to redraw the brushstrokes
- InvalidateRect(hwnd, NULL, TRUE);
- }
- }
- }*/
- //end chatgpt new modified code
- //start working but no erase history code (adding brushstruct for eraser logic) fallbackcode
- MSG msg = {};
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- //end working but no erase history code fallbackcode
- return 0;
- }
Add Comment
Please, Sign In to add comment