// 26 april 2015 #include "uipriv_windows.h" static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { uiContainer *cc; struct container *c; CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; HWND control; NMHDR *nm = (NMHDR *) lParam; RECT r; HDC dc; PAINTSTRUCT ps; cc = uiContainer(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); if (cc == NULL) if (uMsg == WM_NCCREATE) SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams)); // DO NOT RETURN DEFWINDOWPROC() HERE // see the next block of comments as to why // instead, we simply check if c == NULL again later switch (uMsg) { // these are only run if c is not NULL case WM_PAINT: if (cc == NULL) break; c = (struct container *) (uiControl(cc)->Internal); dc = BeginPaint(c->hwnd, &ps); if (dc == NULL) logLastError("error beginning container paint in containerWndProc()"); r = ps.rcPaint; paintContainerBackground(c->hwnd, dc, &r); EndPaint(c->hwnd, &ps); return 0; // tab controls use this to draw the background of the tab area case WM_PRINTCLIENT: if (cc == NULL) break; c = (struct container *) (uiControl(cc)->Internal); if (GetClientRect(c->hwnd, &r) == 0) logLastError("error getting client rect in containerWndProc()"); paintContainerBackground(c->hwnd, (HDC) wParam, &r); return 0; case WM_ERASEBKGND: // avoid some flicker // we draw the whole update area anyway return 1; case msgUpdateChild: if (cc == NULL) break; c = (struct container *) (uiControl(cc)->Internal); if (GetClientRect(c->hwnd, &r) == 0) logLastError("error getting client rect for resize in containerWndProc()"); resize(cc, &r); // we used SWP_NOREDRAW for each resize so we can do this here if (InvalidateRect(c->hwnd, NULL, TRUE) == 0) logLastError("error queueing redraw after resize in containerWndProc()"); return 0; } return DefWindowProcW(hwnd, uMsg, wParam, lParam); } // subclasses override this and call back here when all children are destroyed static void containerDestroy(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); if (c->parent != NULL) complain("attempt to destroy uiContainer %p while it has a parent", cc); if (DestroyWindow(c->hwnd) == 0) logLastError("error destroying uiContainer window in containerDestroy()"); uiFree(c); } static uintptr_t containerHandle(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); return (uintptr_t) (c->hwnd); } static void containerSetParent(uiControl *cc, uiContainer *parent) { struct container *c = (struct container *) (cc->Internal); uiContainer *oldparent; HWND newparent; oldparent = c->parent; c->parent = parent; newparent = initialParent; if (c->parent != NULL) newparent = (HWND) uiControlHandle(uiControl(c->parent)); if (SetParent(c->hwnd, newparent) == 0) logLastError("error changing uiContainer parent in containerSetParent()"); } static void containerResize(uiControl *cc, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) { struct container *c = (struct container *) (cc->Internal); moveAndReorderWindow(c->hwnd, d->Sys->InsertAfter, x, y, width, height); d->Sys->InsertAfter = c->hwnd; SendMessageW(c->hwnd, msgUpdateChild, 0, 0); } static int containerVisible(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); return !c->hidden; } static void containerShow(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); ShowWindow(c->hwnd, SW_SHOW); // hidden controls don't count in boxes and grids c->hidden = 0; if (c->parent != NULL) uiContainerUpdate(c->parent); } static void containerHide(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); ShowWindow(c->hwnd, SW_HIDE); c->hidden = 1; if (c->parent != NULL) uiContainerUpdate(c->parent); } static void containerEnable(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); uiControlSysFuncParams p; EnableWindow(c->hwnd, TRUE); p.Func = uiWindowsSysFuncContainerEnable; uiControlSysFunc(cc, &p); } static void containerDisable(uiControl *cc) { struct container *c = (struct container *) (cc->Internal); uiControlSysFuncParams p; EnableWindow(c->hwnd, FALSE); p.Func = uiWindowsSysFuncContainerDisable; uiControlSysFunc(cc, &p); } static void containerUpdate(uiContainer *cc) { struct container *c = (struct container *) (uiControl(cc)->Internal); SendMessageW(c->hwnd, msgUpdateChild, 0, 0); } void uiMakeContainer(uiContainer *cc) { struct container *c; c = uiNew(struct container); c->hwnd = CreateWindowExW(WS_EX_CONTROLPARENT, containerClass, L"", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, initialParent, NULL, hInstance, cc); if (c->hwnd == NULL) logLastError("error creating uiContainer window in uiMakeContainer()"); uiControl(cc)->Internal = c; uiControl(cc)->Destroy = containerDestroy; uiControl(cc)->Handle = containerHandle; uiControl(cc)->SetParent = containerSetParent; // PreferredSize() is provided by subclasses uiControl(cc)->Resize = containerResize; uiControl(cc)->Visible = containerVisible; uiControl(cc)->Show = containerShow; uiControl(cc)->Hide = containerHide; uiControl(cc)->Enable = containerEnable; uiControl(cc)->Disable = containerDisable; // ResizeChildren() is provided by subclasses uiContainer(cc)->Update = containerUpdate; }