// 8 september 2015 #include "uipriv_windows.hpp" #include "area.hpp" // TODO handle WM_DESTROY/WM_NCDESTROY // TODO same for other Direct2D stuff static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { uiArea *a; CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; RECT client; WINDOWPOS *wp = (WINDOWPOS *) lParam; LRESULT lResult; a = (uiArea *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); if (a == NULL) { if (uMsg == WM_CREATE) { a = (uiArea *) (cs->lpCreateParams); // assign a->hwnd here so we can use it immediately a->hwnd = hwnd; SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) a); } // fall through to DefWindowProcW() anyway return DefWindowProcW(hwnd, uMsg, wParam, lParam); } // always recreate the render target if necessary if (!a->openGL) { if (a->rt == NULL) a->rt = makeHWNDRenderTarget(a->hwnd); } if (areaDoDraw(a, uMsg, wParam, lParam, &lResult) != FALSE) return lResult; if (uMsg == WM_WINDOWPOSCHANGED) { if ((wp->flags & SWP_NOSIZE) != 0) return DefWindowProcW(hwnd, uMsg, wParam, lParam); a->width = -1; a->height = -1; uiWindowsEnsureGetClientRect(a->hwnd, &client); areaDrawOnResize(a, &client); areaScrollOnResize(a, &client); { double w, h; loadAreaSize(a, &w, &h); a->ah->Resize(a->ah, a, (int)w, (int)h); } return 0; } if (areaDoScroll(a, uMsg, wParam, lParam, &lResult) != FALSE) return lResult; if (areaDoEvents(a, uMsg, wParam, lParam, &lResult) != FALSE) return lResult; // nothing done return DefWindowProc(hwnd, uMsg, wParam, lParam); } // control implementation uiWindowsControlAllDefaultsExceptDestroy(uiArea) static void uiAreaDestroy(uiControl *c) { uiArea* a = uiArea(c); if (a->openGL && a->glcontext) freeGLContext(a->glcontext); uiWindowsEnsureDestroyWindow(a->hwnd); uiFreeControl(c); } static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height) { *width = c->c.MinWidth; if (*width < 1) *width = 1; *height = c->c.MinHeight; if (*height < 1) *height = 1; } ATOM registerAreaClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) { WNDCLASSW wc; ZeroMemory(&wc, sizeof (WNDCLASSW)); wc.lpszClassName = areaClass; wc.lpfnWndProc = areaWndProc; wc.hInstance = hInstance; wc.hIcon = hDefaultIcon; wc.hCursor = hDefaultCursor; wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); // this is just to be safe; see the InvalidateRect() call in the WM_WINDOWPOSCHANGED handler for more details wc.style = CS_HREDRAW | CS_VREDRAW; return RegisterClassW(&wc); } void unregisterArea(void) { if (UnregisterClassW(areaClass, hInstance) == 0) logLastError(L"error unregistering uiArea window class"); } void uiAreaSetSize(uiArea *a, int width, int height) { a->scrollWidth = width; a->scrollHeight = height; areaUpdateScroll(a); } void uiAreaQueueRedrawAll(uiArea *a) { // don't erase the background; we do that ourselves in doPaint() invalidateRect(a->hwnd, NULL, FALSE); } void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) { // TODO } void uiAreaBeginUserWindowMove(uiArea *a) { HWND toplevel; // TODO restrict execution ReleaseCapture(); // TODO use properly and reset internal data structures toplevel = parentToplevel(a->hwnd); if (toplevel == NULL) { // TODO return; } // see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654 SendMessageW(toplevel, WM_SYSCOMMAND, SC_MOVE | 2, 0); } void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) { HWND toplevel; WPARAM wParam; // TODO restrict execution ReleaseCapture(); // TODO use properly and reset internal data structures toplevel = parentToplevel(a->hwnd); if (toplevel == NULL) { // TODO return; } // see http://stackoverflow.com/questions/40249940/how-do-i-initiate-a-user-mouse-driven-move-or-resize-for-custom-window-borders-o#40250654 wParam = SC_SIZE; switch (edge) { case uiWindowResizeEdgeLeft: wParam |= 1; break; case uiWindowResizeEdgeTop: wParam |= 3; break; case uiWindowResizeEdgeRight: wParam |= 2; break; case uiWindowResizeEdgeBottom: wParam |= 6; break; case uiWindowResizeEdgeTopLeft: wParam |= 4; break; case uiWindowResizeEdgeTopRight: wParam |= 5; break; case uiWindowResizeEdgeBottomLeft: wParam |= 7; break; case uiWindowResizeEdgeBottomRight: wParam |= 8; break; } SendMessageW(toplevel, WM_SYSCOMMAND, wParam, 0); } void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b) { a->bgR = r; a->bgG = g; a->bgB = b; } uiArea *uiNewArea(uiAreaHandler *ah) { uiArea *a; uiWindowsNewControl(uiArea, a); a->width = -1; a->height = -1; a->ah = ah; a->scrolling = FALSE; clickCounterReset(&(a->cc)); // a->hwnd is assigned in areaWndProc() uiWindowsEnsureCreateControlHWND(0, areaClass, L"", 0, hInstance, a, FALSE); uiAreaSetBackgroundColor(a, -1, -1, -1); a->openGL = 0; return a; } uiGLContext *uiAreaGetGLContext(uiArea* a) { if (!a->openGL) userbug("trying to get GL context from non-GL area"); return a->glcontext; } uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions) { uiArea *a; uiWindowsNewControl(uiArea, a); a->width = -1; a->height = -1; a->ah = ah; a->scrolling = FALSE; clickCounterReset(&(a->cc)); // a->hwnd is assigned in areaWndProc() uiWindowsEnsureCreateControlHWND(0, areaClass, L"", 0, hInstance, a, FALSE); uiAreaSetBackgroundColor(a, -1, -1, -1); a->openGL = 1; for (int i = 0; req_versions[i]; i++) { int major = uiGLVerMajor(req_versions[i]); int minor = uiGLVerMinor(req_versions[i]); a->glcontext = createGLContext(a, major, minor); if (a->glcontext) break; } return a; } uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) { uiArea *a; uiWindowsNewControl(uiArea, a); a->width = -1; a->height = -1; a->ah = ah; a->scrolling = TRUE; a->scrollWidth = width; a->scrollHeight = height; clickCounterReset(&(a->cc)); // a->hwnd is assigned in areaWndProc() uiWindowsEnsureCreateControlHWND(0, areaClass, L"", WS_HSCROLL | WS_VSCROLL, hInstance, a, FALSE); uiAreaSetBackgroundColor(a, -1, -1, -1); a->openGL = 0; // TODO, eventually??? // set initial scrolling parameters areaUpdateScroll(a); return a; }