Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ==++ Here's the full code for (file 1/2) of "Infinite-Canvas.cpp"::: ++==
- ```Infinite-Canvas.cpp
- #define NOMINMAX
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <windowsx.h>
- #include <commctrl.h>
- #include <commdlg.h>
- #include <cmath>
- #include <vector>
- #include <mutex>
- #include <fstream>
- #include <thread>
- #include <algorithm>
- #include "resource.h"
- #pragma comment(lib, "comctl32.lib")
- struct DrawPoint {
- int x, y;
- DWORD timestamp;
- DrawPoint() : x(0), y(0), timestamp(0) {}
- DrawPoint(int px, int py) : x(px), y(py), timestamp(GetTickCount()) {}
- };
- struct SerializedStroke {
- std::vector<DrawPoint> points;
- COLORREF color;
- int brushSize;
- bool isEraser;
- };
- std::mutex strokeMutex;
- std::vector<SerializedStroke> strokeHistory;
- std::vector<DrawPoint> strokeBuffer;
- const double MIN_DISTANCE = 2.0;
- COLORREF currentBrushColor = RGB(24, 123, 205);
- int brushSize = 10;
- bool isDrawing = false;
- bool isEraserMode = false;
- bool isPaintbrushSelected = true;
- bool isSpacePressed = false;
- POINT lastMousePos = { 0, 0 };
- int scrollX = 0;
- int scrollY = 0;
- float gridZoomFactor = 1.0f;
- bool showGrid = true;
- bool useAlphaGrid = false;
- int gridOpacity = 255;
- const int GRID_SIZE = 100;
- HINSTANCE hInst;
- HWND hWnd;
- HDC hOffscreenDC = NULL;
- HBITMAP hOffscreenBitmap = NULL;
- HWND hStatusBar = NULL;
- DWORD lastStatusUpdateTime = 0;
- const DWORD STATUS_UPDATE_INTERVAL = 50;
- HDC hStatusBufferDC = NULL;
- HBITMAP hStatusBufferBitmap = NULL;
- int lastOffscreenScrollX = 0;
- int lastOffscreenScrollY = 0;
- const wchar_t* STATE_FILE = L"canvas_state2.bin";
- bool isLoading = false;
- bool sessionDirty = false;
- // Save the current canvas settings and strokes to disk.
- void SaveCanvasState() {
- std::ofstream file(STATE_FILE, std::ios::binary | std::ios::out);
- if (!file)
- return;
- file.write(reinterpret_cast<const char*>(&gridZoomFactor), sizeof(float));
- file.write(reinterpret_cast<const char*>(&showGrid), sizeof(bool));
- file.write(reinterpret_cast<const char*>(&useAlphaGrid), sizeof(bool));
- file.write(reinterpret_cast<const char*>(&gridOpacity), sizeof(int));
- file.write(reinterpret_cast<const char*>(¤tBrushColor), sizeof(COLORREF));
- file.write(reinterpret_cast<const char*>(&brushSize), sizeof(int));
- {
- std::lock_guard<std::mutex> lock(strokeMutex);
- size_t strokeCount = strokeHistory.size();
- file.write(reinterpret_cast<const char*>(&strokeCount), sizeof(size_t));
- for (const auto& stroke : strokeHistory) {
- std::vector<DrawPoint> optimizedPoints;
- if (!stroke.points.empty()) {
- optimizedPoints.push_back(stroke.points[0]);
- for (size_t i = 1; i < stroke.points.size(); ++i) {
- const DrawPoint& prev = optimizedPoints.back();
- const DrawPoint& curr = stroke.points[i];
- double dx = curr.x - prev.x;
- double dy = curr.y - prev.y;
- double distance = sqrt(dx * dx + dy * dy);
- if (distance >= MIN_DISTANCE)
- optimizedPoints.push_back(curr);
- }
- }
- size_t pointCount = optimizedPoints.size();
- file.write(reinterpret_cast<const char*>(&pointCount), sizeof(size_t));
- if (pointCount > 0)
- file.write(reinterpret_cast<const char*>(optimizedPoints.data()), pointCount * sizeof(DrawPoint));
- file.write(reinterpret_cast<const char*>(&stroke.color), sizeof(COLORREF));
- file.write(reinterpret_cast<const char*>(&stroke.brushSize), sizeof(int));
- file.write(reinterpret_cast<const char*>(&stroke.isEraser), sizeof(bool));
- }
- }
- file.close();
- }
- // Asynchronously load the saved canvas state from disk.
- void LoadCanvasStateAsync(HWND hwnd) {
- isLoading = true;
- std::thread([hwnd]() {
- std::ifstream file(STATE_FILE, std::ios::binary | std::ios::in);
- if (!file) {
- isLoading = false;
- return;
- }
- try {
- file.read(reinterpret_cast<char*>(&gridZoomFactor), sizeof(float));
- file.read(reinterpret_cast<char*>(&showGrid), sizeof(bool));
- file.read(reinterpret_cast<char*>(&useAlphaGrid), sizeof(bool));
- file.read(reinterpret_cast<char*>(&gridOpacity), sizeof(int));
- file.read(reinterpret_cast<char*>(¤tBrushColor), sizeof(COLORREF));
- file.read(reinterpret_cast<char*>(&brushSize), sizeof(int));
- size_t strokeCount = 0;
- file.read(reinterpret_cast<char*>(&strokeCount), sizeof(size_t));
- std::vector<SerializedStroke> loadedStrokes;
- for (size_t i = 0; i < strokeCount && file.good(); ++i) {
- SerializedStroke stroke;
- size_t pointCount = 0;
- file.read(reinterpret_cast<char*>(&pointCount), sizeof(size_t));
- if (pointCount > 0 && pointCount < 1000000) {
- for (size_t j = 0; j < pointCount; ++j) {
- DrawPoint point;
- file.read(reinterpret_cast<char*>(&point.x), sizeof(int));
- file.read(reinterpret_cast<char*>(&point.y), sizeof(int));
- file.read(reinterpret_cast<char*>(&point.timestamp), sizeof(DWORD));
- stroke.points.push_back(point);
- }
- file.read(reinterpret_cast<char*>(&stroke.color), sizeof(COLORREF));
- file.read(reinterpret_cast<char*>(&stroke.brushSize), sizeof(int));
- file.read(reinterpret_cast<char*>(&stroke.isEraser), sizeof(bool));
- loadedStrokes.push_back(stroke);
- }
- }
- {
- std::lock_guard<std::mutex> lock(strokeMutex);
- strokeHistory = std::move(loadedStrokes);
- }
- }
- catch (...) {
- isLoading = false;
- return;
- }
- file.close();
- isLoading = false;
- InvalidateRect(hwnd, NULL, TRUE);
- }).detach();
- }
- // Draw a smooth stroke using the given points (adjusted by the view offsets).
- void DrawSmoothStroke(HDC hdc, const std::vector<DrawPoint>& points, bool isEraser, COLORREF strokeColor, int strokeSize, int offsetX, int offsetY) {
- if (points.empty())
- return;
- COLORREF color = isEraser ? RGB(255, 255, 255) : strokeColor;
- HBRUSH brush = CreateSolidBrush(color);
- HPEN pen = CreatePen(PS_SOLID, 1, color);
- HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, brush);
- HPEN oldPen = (HPEN)SelectObject(hdc, pen);
- if (points.size() == 1) {
- const DrawPoint& pt = points[0];
- Ellipse(hdc, pt.x - offsetX - strokeSize, pt.y - offsetY - strokeSize,
- pt.x - offsetX + strokeSize, pt.y - offsetY + strokeSize);
- }
- else {
- 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 = std::max(1, (int)(distance / 2));
- 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);
- Ellipse(hdc, x - offsetX - strokeSize, y - offsetY - strokeSize,
- x - offsetX + strokeSize, y - offsetY + strokeSize);
- }
- }
- }
- }
- SelectObject(hdc, oldBrush);
- SelectObject(hdc, oldPen);
- DeleteObject(brush);
- DeleteObject(pen);
- }
- // Draw grid lines relative to the current view offsets.
- void DrawGrid(HDC hdc, const RECT& clientRect) {
- SetBkMode(hdc, TRANSPARENT);
- HPEN gridPen = CreatePen(PS_SOLID, 1, RGB(255, 140, 0));
- HPEN oldPen = (HPEN)SelectObject(hdc, gridPen);
- int scaledGridSize = (int)(GRID_SIZE * gridZoomFactor);
- int modX = scrollX % scaledGridSize;
- if (modX < 0)
- modX += scaledGridSize;
- int startX = -modX;
- for (int x = startX; x < (int)clientRect.right; x += scaledGridSize) {
- MoveToEx(hdc, x, 0, NULL);
- LineTo(hdc, x, clientRect.bottom);
- }
- int modY = scrollY % scaledGridSize;
- if (modY < 0)
- modY += scaledGridSize;
- int startY = -modY;
- for (int y = startY; y < (int)clientRect.bottom; y += scaledGridSize) {
- MoveToEx(hdc, 0, y, NULL);
- LineTo(hdc, clientRect.right, y);
- }
- SelectObject(hdc, oldPen);
- DeleteObject(gridPen);
- }
- // Helper: Redraw all strokes into the persistent offscreen buffer.
- void UpdateOffscreenBuffer(HWND hwnd) {
- RECT rc;
- GetClientRect(hwnd, &rc);
- // Clear offscreen DC with a white background:
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(hOffscreenDC, &rc, whiteBrush);
- DeleteObject(whiteBrush);
- // Redraw all strokes into hOffscreenDC:
- {
- std::lock_guard<std::mutex> lock(strokeMutex);
- for (const auto& stroke : strokeHistory) {
- DrawSmoothStroke(hOffscreenDC, stroke.points, stroke.isEraser, stroke.color, stroke.brushSize, scrollX, scrollY);
- }
- }
- }
- void InitializeStatusBuffer(HWND hStatus) {
- if (hStatusBufferDC) {
- DeleteDC(hStatusBufferDC);
- DeleteObject(hStatusBufferBitmap);
- }
- HDC hdc = GetDC(hStatus);
- RECT rect;
- GetClientRect(hStatus, &rect);
- hStatusBufferDC = CreateCompatibleDC(hdc);
- hStatusBufferBitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
- SelectObject(hStatusBufferDC, hStatusBufferBitmap);
- ReleaseDC(hStatus, hdc);
- }
- void UpdateStatus(HWND hwnd) {
- DWORD currentTime = GetTickCount();
- if (currentTime - lastStatusUpdateTime < STATUS_UPDATE_INTERVAL)
- return;
- lastStatusUpdateTime = currentTime;
- if (!hStatusBar)
- return;
- if (!hStatusBufferDC) {
- InitializeStatusBuffer(hStatusBar);
- }
- RECT statusRect;
- GetClientRect(hStatusBar, &statusRect);
- wchar_t status[512];
- BYTE r = GetRValue(currentBrushColor);
- BYTE g = GetGValue(currentBrushColor);
- BYTE b = GetBValue(currentBrushColor);
- // Here you can adjust what "Canvas Pos" means. For example, using scrollX and scrollY:
- swprintf_s(status, 512,
- 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,
- scrollX, scrollY // Use scrollX and scrollY directly
- );
- SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)status);
- }
- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- switch (uMsg) {
- case WM_CREATE:
- {
- hStatusBar = CreateWindowEx(
- 0,
- STATUSCLASSNAME,
- NULL,
- WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
- 0, 0, 0, 0,
- hwnd,
- (HMENU)0,
- hInst,
- NULL
- );
- if (hStatusBar) {
- int statwidths[] = { -1 };
- SendMessage(hStatusBar, SB_SETPARTS, 1, (LPARAM)statwidths);
- UpdateStatus(hwnd); // Update the status bar text on creation.
- }
- // **** Insert Offscreen Buffer Initialization Here ****
- HDC hdc = GetDC(hwnd);
- RECT rc;
- GetClientRect(hwnd, &rc);
- hOffscreenDC = CreateCompatibleDC(hdc);
- hOffscreenBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
- SelectObject(hOffscreenDC, hOffscreenBitmap);
- HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(hOffscreenDC, &rc, whiteBrush);
- DeleteObject(whiteBrush);
- ReleaseDC(hwnd, hdc);
- // **** End Offscreen Buffer Initialization ****
- LoadCanvasStateAsync(hwnd);
- return 0;
- }
- case WM_KEYDOWN:
- {
- if (GetKeyState(VK_MENU) & 0x8000)
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- if (wParam == VK_SPACE && !isSpacePressed) {
- isSpacePressed = true;
- GetCursorPos(&lastMousePos);
- ScreenToClient(hwnd, &lastMousePos);
- SetCursor(LoadCursor(NULL, IDC_SIZEALL));
- SetCapture(hwnd);
- }
- else if (wParam == 0x50) {
- isPaintbrushSelected = true;
- isEraserMode = false;
- UpdateStatus(hwnd); // <-- Added here
- }
- else if (wParam == 0x45) {
- isPaintbrushSelected = false;
- isEraserMode = true;
- UpdateStatus(hwnd); // <-- Added here
- }
- else if (wParam == 'Q') {
- 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); // <-- Added here
- }
- else if (wParam == VK_ADD || wParam == VK_OEM_PLUS) {
- brushSize = std::min(50, brushSize + 5);
- UpdateStatus(hwnd); // <-- Added here
- }
- else if (wParam == VK_SUBTRACT || wParam == VK_OEM_MINUS) {
- brushSize = std::max(5, brushSize - 5);
- UpdateStatus(hwnd); // <-- Added here
- }
- else if (wParam == 0x43) {
- std::lock_guard<std::mutex> lock(strokeMutex);
- strokeHistory.clear();
- sessionDirty = true; // Mark session as changed due to canvas clear.
- InvalidateRect(hwnd, NULL, TRUE);
- }
- else if (wParam == VK_HOME) {
- scrollX = 0;
- scrollY = 0;
- lastOffscreenScrollX = 0; // if you're tracking these
- lastOffscreenScrollY = 0;
- UpdateOffscreenBuffer(hwnd); // Rebuild the offscreen canvas with (0,0) offsets
- UpdateStatus(hwnd);
- InvalidateRect(hwnd, NULL, TRUE);
- }
- else if (wParam == 'G') {
- showGrid = !showGrid;
- //UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == 'A') {
- useAlphaGrid = !useAlphaGrid;
- UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == VK_PRIOR) {
- gridZoomFactor *= 1.1f;
- UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == VK_NEXT) {
- gridZoomFactor *= 0.9f;
- if (gridZoomFactor < 0.1f)
- gridZoomFactor = 0.1f;
- UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == VK_OEM_6 && useAlphaGrid) {
- gridOpacity = std::min(255, gridOpacity + 15);
- UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == VK_OEM_4 && useAlphaGrid) {
- gridOpacity = std::max(0, gridOpacity - 15);
- UpdateStatus(hwnd); // <-- Added here
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (wParam == VK_ESCAPE) {
- if (isSpacePressed) {
- isSpacePressed = false;
- ReleaseCapture();
- }
- if (sessionDirty) { // Save only if there are unsaved changes.
- SaveCanvasState();
- sessionDirty = false;
- }
- PostQuitMessage(0);
- return 0;
- }
- else if (wParam == VK_F1) {
- MessageBox(hwnd, L"Infinite Canvas Doodle App (Infinite canvas with session serialization)\nI 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! (1383/561 lines of code) by Entisoft Software (c) Evans Thorpemorton pen=24,123,205 Teal", L"Information", MB_OK | MB_ICONINFORMATION);
- return 0;
- }
- return 0;
- }
- case WM_KEYUP:
- {
- if (wParam == VK_SPACE) {
- isSpacePressed = false;
- SetCursor(LoadCursor(NULL, IDC_ARROW));
- ReleaseCapture();
- return 0;
- }
- return 0;
- }
- case WM_LBUTTONDOWN:
- {
- isDrawing = true;
- int worldX = GET_X_LPARAM(lParam) + scrollX;
- int worldY = GET_Y_LPARAM(lParam) + scrollY;
- strokeBuffer.clear();
- strokeBuffer.push_back(DrawPoint(worldX, worldY));
- SetCapture(hwnd);
- InvalidateRect(hwnd, NULL, FALSE);
- return 0;
- }
- case WM_LBUTTONUP:
- {
- if (isDrawing) {
- isDrawing = false;
- SerializedStroke stroke;
- stroke.points = strokeBuffer;
- stroke.color = currentBrushColor;
- stroke.brushSize = brushSize;
- stroke.isEraser = isEraserMode;
- {
- std::lock_guard<std::mutex> lock(strokeMutex);
- strokeHistory.push_back(stroke);
- }
- strokeBuffer.clear();
- ReleaseCapture();
- InvalidateRect(hwnd, NULL, FALSE);
- sessionDirty = true; // Mark that the canvas has changed.
- if (sessionDirty) { // Only save if changes were made.
- SaveCanvasState();
- sessionDirty = false; // Reset the flag after saving.
- }
- UpdateOffscreenBuffer(hwnd); // Update the persistent offscreen canvas.
- UpdateStatus(hwnd); // Update status bar.
- }
- return 0;
- }
- case WM_MOUSEMOVE:
- {
- int x = GET_X_LPARAM(lParam);
- int y = GET_Y_LPARAM(lParam);
- if (isSpacePressed) {
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- int deltaX = x - lastMousePos.x;
- int deltaY = y - lastMousePos.y;
- scrollX -= deltaX;
- scrollY -= deltaY;
- lastMousePos.x = x;
- lastMousePos.y = y;
- // After updating scrollX and scrollY in the panning branch:
- if (scrollX != lastOffscreenScrollX || scrollY != lastOffscreenScrollY) {
- UpdateOffscreenBuffer(hwnd);
- lastOffscreenScrollX = scrollX;
- lastOffscreenScrollY = scrollY;
- }
- UpdateStatus(hwnd); // <-- Added to update Canvas Pos
- InvalidateRect(hwnd, NULL, FALSE);
- }
- else if (isDrawing && (wParam & MK_LBUTTON)) {
- int worldX = x + scrollX;
- int worldY = y + scrollY;
- if (strokeBuffer.empty())
- strokeBuffer.push_back(DrawPoint(worldX, worldY));
- else {
- const DrawPoint& lastPt = strokeBuffer.back();
- double dx = worldX - lastPt.x;
- double dy = worldY - lastPt.y;
- double distance = sqrt(dx * dx + dy * dy);
- if (distance >= MIN_DISTANCE)
- strokeBuffer.push_back(DrawPoint(worldX, worldY));
- }
- //InvalidateRect(hwnd, NULL, FALSE);
- // Compute dirty rectangle for the new segment
- worldX = x + scrollX;
- worldY = y + scrollY;
- if (!strokeBuffer.empty()) {
- const DrawPoint& prevPt = strokeBuffer.back();
- // Convert world coordinates to client coordinates
- int clientPrevX = prevPt.x - scrollX;
- int clientPrevY = prevPt.y - scrollY;
- int clientNewX = worldX - scrollX;
- int clientNewY = worldY - scrollY;
- RECT dirty;
- dirty.left = std::min(clientPrevX, clientNewX) - brushSize;
- dirty.top = std::min(clientPrevY, clientNewY) - brushSize;
- dirty.right = std::max(clientPrevX, clientNewX) + brushSize;
- dirty.bottom = std::max(clientPrevY, clientNewY) + brushSize;
- InvalidateRect(hwnd, &dirty, FALSE);
- }
- else {
- InvalidateRect(hwnd, NULL, FALSE);
- }
- }
- return 0;
- }
- case WM_SIZE:
- {
- RECT rcClient;
- GetClientRect(hwnd, &rcClient);
- if (hStatusBar) {
- RECT rcSB;
- SendMessage(hStatusBar, SB_GETRECT, 0, (LPARAM)&rcSB);
- int sbHeight = rcSB.bottom - rcSB.top;
- MoveWindow(hStatusBar, 0, rcClient.bottom - sbHeight, rcClient.right, sbHeight, TRUE);
- }
- // Recreate offscreen buffer with new client area size:
- if (hOffscreenDC) {
- DeleteDC(hOffscreenDC);
- hOffscreenDC = NULL;
- }
- if (hOffscreenBitmap) {
- DeleteObject(hOffscreenBitmap);
- hOffscreenBitmap = NULL;
- }
- HDC hdc = GetDC(hwnd);
- hOffscreenDC = CreateCompatibleDC(hdc);
- hOffscreenBitmap = CreateCompatibleBitmap(hdc, rcClient.right, rcClient.bottom);
- SelectObject(hOffscreenDC, hOffscreenBitmap);
- ReleaseDC(hwnd, hdc);
- // Redraw the offscreen buffer with all strokes:
- UpdateOffscreenBuffer(hwnd);
- UpdateStatus(hwnd);
- // After UpdateOffscreenBuffer(hwnd);
- lastOffscreenScrollX = scrollX;
- lastOffscreenScrollY = scrollY;
- InvalidateRect(hwnd, NULL, TRUE);
- return 0;
- }
- case WM_ERASEBKGND:
- return 1;
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- // Copy the persistent offscreen canvas to the screen:
- BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, hOffscreenDC, 0, 0, SRCCOPY);
- // If a stroke is in progress, overlay it:
- if (isDrawing && !strokeBuffer.empty())
- DrawSmoothStroke(hdc, strokeBuffer, isEraserMode, currentBrushColor, brushSize, scrollX, scrollY);
- // Draw the grid on top:
- if (showGrid)
- DrawGrid(hdc, clientRect);
- EndPaint(hwnd, &ps);
- return 0;
- }
- case WM_SETCURSOR:
- {
- if (LOWORD(lParam) == HTCLIENT) {
- 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);
- }
- case WM_DESTROY:
- {
- if (sessionDirty) { // Save only if there are unsaved changes.
- SaveCanvasState();
- sessionDirty = false;
- }
- PostQuitMessage(0);
- return 0;
- }
- default:
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- return 0;
- }
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
- INITCOMMONCONTROLSEX icex = { sizeof(INITCOMMONCONTROLSEX), ICC_BAR_CLASSES };
- InitCommonControlsEx(&icex);
- const wchar_t CLASS_NAME[] = L"InfiniteCanvasClass";
- WNDCLASS wc = {};
- wc.lpfnWndProc = WindowProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASS_NAME;
- wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
- RegisterClass(&wc);
- hInst = hInstance;
- hWnd = CreateWindowEx(0, 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, PgUp=ZoomIn, PgDn=ZoomOut, F1=About)",
- WS_OVERLAPPEDWINDOW | WS_MAXIMIZE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL, NULL, hInstance, NULL);
- if (hWnd == NULL)
- return 0;
- SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED);
- //ShowWindow(hWnd, nCmdShow);
- ShowWindow(hWnd, SW_SHOWMAXIMIZED);
- MSG msg = {};
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- ```
- ==++ Here's the full code for (file 2/2) of "resource.h"::: ++==
- ```resource.h
- //{{NO_DEPENDENCIES}}
- // Microsoft Visual C++ generated include file.
- // Used by DoodleApp.rc
- //
- #define IDI_ICON1 101
- // Next default values for new objects
- //
- #ifdef APSTUDIO_INVOKED
- #ifndef APSTUDIO_READONLY_SYMBOLS
- #define _APS_NEXT_RESOURCE_VALUE 102
- #define _APS_NEXT_COMMAND_VALUE 40001
- #define _APS_NEXT_CONTROL_VALUE 1001
- #define _APS_NEXT_SYMED_VALUE 101
- #endif
- #endif
- ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement