#include "precomp.h" static const TCHAR szImageEditWndClass[] = TEXT("ImageSoftEditWndClass"); #define IMAGE_FRAME_SIZE 1 static VOID EditWndUpdateScrollInfo(PEDIT_WND_INFO Info) { SCROLLINFO si; RECT rcClient; GetClientRect(Info->hSelf, &rcClient); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_RANGE; si.nPage = rcClient.right - (2 * IMAGE_FRAME_SIZE); si.nMin = 0; si.nMax = Info->Width; SetScrollInfo(Info->hSelf, SB_HORZ, &si, TRUE); si.nPage = rcClient.bottom - (2 * IMAGE_FRAME_SIZE); si.nMax = Info->Height; SetScrollInfo(Info->hSelf, SB_VERT, &si, TRUE); } static BOOL LoadBlankCanvas(PEDIT_WND_INFO Info) { /* FIXME: convert this to a DIB Section */ /* set bitmap dimensions */ Info->Width = Info->OpenInfo->New.Width; Info->Height = Info->OpenInfo->New.Height; return TRUE; } static BOOL LoadDIBImage(PEDIT_WND_INFO Info) { BITMAPFILEHEADER bmfh; HANDLE hFile; BITMAP bitmap; DWORD BytesRead; BOOL bSuccess, bRet = FALSE; hFile = CreateFile(Info->OpenInfo->Open.lpImagePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) return bRet; bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &BytesRead, NULL); if (bSuccess && (BytesRead == sizeof(BITMAPFILEHEADER)) && (bmfh.bfType == *(WORD *)"BM")) { DWORD InfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER); Info->pbmi = HeapAlloc(ProcessHeap, 0, InfoSize); if (Info->pbmi) { bSuccess = ReadFile(hFile, Info->pbmi, InfoSize, &BytesRead, NULL); if (bSuccess && (BytesRead == InfoSize)) { Info->hBitmap = CreateDIBSection(NULL, Info->pbmi, DIB_RGB_COLORS, (VOID *)&Info->pBits, NULL, 0); if (Info->hBitmap != NULL) { ReadFile(hFile, Info->pBits, bmfh.bfSize - bmfh.bfOffBits, &BytesRead, NULL); GetObject(Info->hBitmap, sizeof(BITMAP), &bitmap); Info->Width = bitmap.bmWidth; Info->Height = bitmap.bmHeight; bRet = TRUE; } } } } else if (!bSuccess) { GetError(0); } CloseHandle(hFile); return bRet; } static BOOL InitEditWnd(PEDIT_WND_INFO Info) { //BOOL bRet = FALSE; Info->Zoom = 100; if (Info->OpenInfo != NULL) { HDC hDC; if (Info->hDCMem) { DeleteObject(Info->hDCMem); Info->hDCMem = NULL; } hDC = GetDC(Info->hSelf); Info->hDCMem = CreateCompatibleDC(hDC); ReleaseDC(Info->hSelf, hDC); if (Info->OpenInfo->CreateNew) { LoadBlankCanvas(Info); } else { LoadDIBImage(Info); } Info->OpenInfo = NULL; } EditWndUpdateScrollInfo(Info); /* Add image editor to the list */ Info->Next = Info->MainWnd->ImageEditors; Info->MainWnd->ImageEditors = Info; InvalidateRect(Info->hSelf, NULL, TRUE); /* FIXME - if returning FALSE, remove the image editor from the list! */ return TRUE; } static VOID DestroyEditWnd(PEDIT_WND_INFO Info) { PEDIT_WND_INFO *PrevEditor; PEDIT_WND_INFO Editor; DeleteDC(Info->hDCMem); /* FIXME - free resources and run down editor */ HeapFree(ProcessHeap, 0, Info->pbmi); HeapFree(ProcessHeap, 0, Info->pBits); /* Remove the image editor from the list */ PrevEditor = &Info->MainWnd->ImageEditors; Editor = Info->MainWnd->ImageEditors; do { if (Editor == Info) { *PrevEditor = Info->Next; break; } PrevEditor = &Editor->Next; Editor = Editor->Next; } while (Editor != NULL); } static VOID ImageEditWndRepaint(PEDIT_WND_INFO Info, HDC hDC, LPPAINTSTRUCT lpps) { HBITMAP hOldBitmap; if (Info->hBitmap) { hOldBitmap = (HBITMAP) SelectObject(Info->hDCMem, Info->hBitmap); BitBlt(hDC, lpps->rcPaint.left, lpps->rcPaint.top, lpps->rcPaint.right - lpps->rcPaint.left, lpps->rcPaint.bottom - lpps->rcPaint.top, Info->hDCMem, lpps->rcPaint.left, lpps->rcPaint.top, SRCCOPY); Info->hBitmap = SelectObject(Info->hDCMem, hOldBitmap); } } static LRESULT CALLBACK ImageEditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PEDIT_WND_INFO Info; LRESULT Ret = 0; HDC hDC; static INT xMouse, yMouse; static BOOL bLeftButtonDown, bRightButtonDown; /* Get the window context */ Info = (PEDIT_WND_INFO)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (Info == NULL && uMsg != WM_CREATE) { goto HandleDefaultMessage; } switch (uMsg) { case WM_CREATE: { Info = (PEDIT_WND_INFO)(((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam); Info->hSelf = hwnd; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)Info); if (!InitEditWnd(Info)) { Ret = (LRESULT)-1; break; } break; } /* case WM_ERASEBKGND: if (Info->Width != 0 && Info->Height != 0) { Ret = TRUE; } break; */ case WM_LBUTTONDOWN: if (! bRightButtonDown) SetCapture(Info->hSelf); bLeftButtonDown = TRUE; xMouse = LOWORD(lParam); yMouse = HIWORD(lParam); SetCursor(LoadCursor(hInstance, MAKEINTRESOURCE(IDC_PAINTBRUSHCURSORMOUSEDOWN))); break; case WM_LBUTTONUP: if (bLeftButtonDown) SetCapture(NULL); bLeftButtonDown = FALSE; break; case WM_RBUTTONDOWN: if (! bLeftButtonDown) SetCapture(Info->hSelf); bRightButtonDown = TRUE; xMouse = LOWORD(lParam); yMouse = HIWORD(lParam); SetCursor(LoadCursor(hInstance, MAKEINTRESOURCE(IDC_PAINTBRUSHCURSORMOUSEDOWN))); break; case WM_RBUTTONUP: if (bRightButtonDown) SetCapture(NULL); bRightButtonDown = FALSE; break; case WM_MOUSEMOVE: { HPEN hPen, hPenOld; if (!bLeftButtonDown && !bRightButtonDown) break; hDC = GetDC(Info->hSelf); SelectObject(Info->hDCMem, Info->hBitmap); if (bLeftButtonDown) hPen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0)); else hPen = CreatePen(PS_SOLID, 3, RGB(255, 255, 255)); hPenOld = SelectObject(hDC, hPen); SelectObject(Info->hDCMem, hPen); MoveToEx(hDC, xMouse, yMouse, NULL); MoveToEx(Info->hDCMem, xMouse, yMouse, NULL); xMouse = (short)LOWORD(lParam); yMouse = (short)HIWORD(lParam); LineTo(hDC, xMouse, yMouse); LineTo(Info->hDCMem, xMouse, yMouse); SelectObject(hDC, hPenOld); DeleteObject(SelectObject(Info->hDCMem, hPenOld)); ReleaseDC(Info->hSelf, hDC); } break; case WM_PAINT: { if (Info->Width != 0 && Info->Height != 0) { PAINTSTRUCT ps; HDC hDC; hDC = BeginPaint(hwnd, &ps); if (hDC != NULL) { ImageEditWndRepaint(Info, hDC, &ps); EndPaint(hwnd, &ps); } } break; } case WM_SIZE: { EditWndUpdateScrollInfo(Info); goto HandleDefaultMessage; } case WM_MENUSELECT: case WM_ENTERMENULOOP: case WM_EXITMENULOOP: /* forward these messages to the main window procedure */ Ret = SendMessage(Info->MainWnd->hSelf, uMsg, wParam, lParam); break; case WM_MDIACTIVATE: /* Switch the main window context if neccessary */ MainWndSwitchEditorContext(Info->MainWnd, (HWND)wParam, (HWND)lParam); break; case WM_DESTROY: { DestroyEditWnd(Info); HeapFree(ProcessHeap, 0, Info); SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); break; } default: HandleDefaultMessage: Ret = DefMDIChildProc(hwnd, uMsg, wParam, lParam); break; } return Ret; } VOID SetImageEditorEnvironment(PEDIT_WND_INFO Info, BOOL Setup) { if (Setup) { /* FIXME - setup editor environment (e.g. show toolbars, enable menus etc) */ } else { /* FIXME - cleanup editor environment (e.g. hide toolbars, disable menus etc) */ } } BOOL CreateImageEditWindow(PMAIN_WND_INFO MainWnd, POPEN_IMAGE_EDIT_INFO OpenInfo) { PEDIT_WND_INFO Info; HWND hWndEditor; LONG Width, Height; Info = HeapAlloc(ProcessHeap, 0, sizeof(EDIT_WND_INFO)); if (Info != NULL) { ZeroMemory(Info, sizeof(EDIT_WND_INFO)); Info->MainWnd = MainWnd; Info->MdiEditorType = metImageEditor; Info->OpenInfo = OpenInfo; if (OpenInfo->CreateNew) { Width = OpenInfo->New.Width; Height = OpenInfo->New.Height; } else { Width = CW_USEDEFAULT; Height = CW_USEDEFAULT; } hWndEditor = CreateMDIWindow(szImageEditWndClass, OpenInfo->lpImageName, WS_HSCROLL | WS_VSCROLL | WS_MAXIMIZE, 200, 200, Width, Height, MainWnd->hMdiClient, hInstance, (LPARAM)Info); if (hWndEditor != NULL) { return TRUE; } HeapFree(ProcessHeap, 0, Info); } return FALSE; } BOOL InitImageEditWindowImpl(VOID) { WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = ImageEditWndProc; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_IMAGESOFTICON)); wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_PAINTBRUSHCURSOR)); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = szImageEditWndClass; wc.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_IMAGESOFTICON), IMAGE_ICON, 16, 16, LR_SHARED); return RegisterClassEx(&wc) != (ATOM)0; } VOID UninitImageEditWindowImpl(VOID) { UnregisterClass(szImageEditWndClass, hInstance); }