| /* |
| * Scroll windows and DCs |
| * |
| * Copyright David W. Metcalfe, 1993 |
| * Alex Korobka 1995 |
| * |
| * |
| */ |
| |
| #include <stdlib.h> |
| #include "wintypes.h" |
| #include "class.h" |
| #include "win.h" |
| #include "gdi.h" |
| #include "sysmetrics.h" |
| #include "stddebug.h" |
| /* #define DEBUG_SCROLL */ |
| #include "debug.h" |
| |
| |
| |
| extern HRGN DCE_GetVisRgn(HWND, WORD); |
| extern HWND CARET_GetHwnd(); |
| |
| static int RgnType; |
| |
| |
| /* ----------------------------------------------------------------------- |
| * SCROLL_TraceChildren |
| * |
| * Returns a region invalidated by children, siblings, and/or ansectors |
| * in the window rectangle or client rectangle |
| * |
| * dcx can have DCX_WINDOW, DCX_CLIPCHILDREN, DCX_CLIPSIBLINGS set |
| */ |
| |
| HRGN SCROLL_TraceChildren( HWND hScroll, short dx, short dy, WORD dcx) |
| { |
| WND *wndScroll = WIN_FindWndPtr( hScroll ); |
| HRGN hRgnWnd; |
| HRGN hUpdateRgn,hCombineRgn; |
| |
| if( !wndScroll || ( !dx && !dy) ) return 0; |
| |
| if( dcx & DCX_WINDOW ) |
| hRgnWnd = CreateRectRgnIndirect(&wndScroll->rectWindow); |
| else |
| { |
| RECT rect; |
| |
| GetClientRect(hScroll,&rect); |
| hRgnWnd = CreateRectRgnIndirect(&rect); |
| } |
| |
| hUpdateRgn = DCE_GetVisRgn( hScroll, dcx ); |
| hCombineRgn = CreateRectRgn(0,0,0,0); |
| |
| if( !hUpdateRgn || !hCombineRgn ) |
| { |
| DeleteObject( hUpdateRgn? hUpdateRgn : hCombineRgn); |
| DeleteObject(hRgnWnd); |
| return 0; |
| } |
| |
| OffsetRgn( hUpdateRgn, dx, dy); |
| CombineRgn(hCombineRgn, hRgnWnd, hUpdateRgn, RGN_DIFF); |
| |
| DeleteObject(hRgnWnd); |
| DeleteObject(hUpdateRgn); |
| |
| return hCombineRgn; |
| } |
| |
| |
| /* ---------------------------------------------------------------------- |
| * SCROLL_ScrollChildren |
| */ |
| BOOL SCROLL_ScrollChildren( HWND hScroll, short dx, short dy) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hScroll); |
| HWND hWnd = wndPtr->hwndChild; |
| HRGN hUpdateRgn; |
| BOOL b = 0; |
| |
| if( !wndPtr || ( !dx && !dy )) return 0; |
| |
| dprintf_scroll(stddeb,"SCROLL_ScrollChildren: hwnd "NPFMT" dx=%i dy=%i\n",hScroll,dx,dy); |
| |
| /* get a region in client rect invalidated by siblings and ansectors */ |
| hUpdateRgn = SCROLL_TraceChildren(hScroll, dx , dy, DCX_CLIPSIBLINGS); |
| |
| /* update children coordinates */ |
| while( hWnd ) |
| { |
| wndPtr = WIN_FindWndPtr( hWnd ); |
| |
| /* we can check if window intersects with clipRect parameter |
| * and do not move it if not - just a thought. - AK |
| */ |
| |
| SetWindowPos(hWnd,0,wndPtr->rectWindow.left + dx, |
| wndPtr->rectWindow.top + dy, 0,0, SWP_NOZORDER | |
| SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | |
| SWP_DEFERERASE ); |
| |
| hWnd = wndPtr->hwndNext; |
| } |
| |
| /* invalidate uncovered region and paint frames */ |
| b = RedrawWindow( hScroll, NULL, hUpdateRgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | |
| RDW_ERASENOW | RDW_ALLCHILDREN ); |
| |
| DeleteObject( hUpdateRgn); |
| return b; |
| } |
| |
| |
| /************************************************************************* |
| * ScrollWindow (USER.61) |
| * |
| * FIXME: a bit broken |
| */ |
| |
| void ScrollWindow(HWND hwnd, short dx, short dy, LPRECT rect, LPRECT clipRect) |
| { |
| HDC hdc; |
| HRGN hrgnUpdate,hrgnClip; |
| RECT rc, cliprc; |
| HWND hCaretWnd = CARET_GetHwnd(); |
| |
| dprintf_scroll(stddeb,"ScrollWindow: dx=%d, dy=%d, lpRect =%08lx clipRect=%i,%i,%i,%i\n", |
| dx, dy, (LONG)rect, (int)((clipRect)?clipRect->left:0), |
| (int)((clipRect)?clipRect->top:0), |
| (int)((clipRect)?clipRect->right:0), |
| (int)((clipRect)?clipRect->bottom:0)); |
| |
| /* if rect is NULL children have to be moved */ |
| if ( !rect ) |
| { |
| GetClientRect(hwnd, &rc); |
| hrgnClip = CreateRectRgnIndirect( &rc ); |
| |
| if ((hCaretWnd == hwnd) || IsChild(hwnd,hCaretWnd)) |
| HideCaret(hCaretWnd); |
| else hCaretWnd = 0; |
| |
| /* children will be Blt'ed too */ |
| hdc = GetDCEx(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS); |
| DeleteObject(hrgnClip); |
| } |
| else |
| { |
| GetClientRect(hwnd,&rc); |
| dprintf_scroll(stddeb,"\trect=%i %i %i %i client=%i %i %i %i\n", |
| (int)rect->left,(int)rect->top,(int)rect->right, |
| (int)rect->bottom,(int)rc.left,(int)rc.top, |
| (int)rc.right,(int)rc.bottom); |
| |
| if (hCaretWnd == hwnd) HideCaret(hCaretWnd); |
| else hCaretWnd = 0; |
| CopyRect(&rc, rect); |
| hdc = GetDC(hwnd); |
| } |
| |
| if (clipRect == NULL) |
| GetClientRect(hwnd, &cliprc); |
| else |
| CopyRect(&cliprc, clipRect); |
| |
| hrgnUpdate = CreateRectRgn(0, 0, 0, 0); |
| ScrollDC(hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL); |
| ReleaseDC(hwnd, hdc); |
| |
| if( !rect ) |
| { |
| /* FIXME: this doesn't take into account hrgnUpdate */ |
| if( !SCROLL_ScrollChildren(hwnd,dx,dy) ) |
| InvalidateRgn(hwnd, hrgnUpdate, TRUE); |
| } |
| else |
| { |
| HRGN hrgnInv = SCROLL_TraceChildren(hwnd,dx,dy,DCX_CLIPCHILDREN | |
| DCX_CLIPSIBLINGS ); |
| if( hrgnInv ) |
| { |
| HRGN hrgnCombine = CreateRectRgn(0,0,0,0); |
| |
| CombineRgn(hrgnCombine,hrgnInv,hrgnUpdate,RGN_OR); |
| dprintf_scroll(stddeb,"ScrollWindow: hrgnComb="NPFMT" hrgnInv="NPFMT" hrgnUpd="NPFMT"\n", |
| hrgnCombine,hrgnInv,hrgnUpdate); |
| |
| DeleteObject(hrgnUpdate); DeleteObject(hrgnInv); |
| hrgnUpdate = hrgnCombine; |
| } |
| |
| RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW); |
| } |
| |
| DeleteObject(hrgnUpdate); |
| if( hCaretWnd ) ShowCaret(hCaretWnd); |
| } |
| |
| |
| /************************************************************************* |
| * ScrollDC (USER.221) |
| * |
| * FIXME: half-broken |
| */ |
| |
| BOOL ScrollDC(HDC hdc, short dx, short dy, LPRECT rc, LPRECT cliprc, |
| HRGN hrgnUpdate, LPRECT rcUpdate) |
| { |
| HRGN hrgnClip, hrgn1, hrgn2; |
| POINT src, dest; |
| short width, height; |
| DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC); |
| |
| dprintf_scroll(stddeb,"ScrollDC: dx=%d dy=%d, hrgnUpdate="NPFMT" rc=%i %i %i %i\n", |
| dx,dy,hrgnUpdate,(int)((rc)?rc->left:0), |
| (int)((rc)?rc->top:0), |
| (int)((rc)?rc->right:0), |
| (int)((rc)?rc->bottom:0)); |
| |
| if (rc == NULL) |
| return FALSE; |
| |
| if (cliprc) |
| { |
| hrgnClip = CreateRectRgnIndirect(cliprc); |
| SelectClipRgn(hdc, hrgnClip); |
| } |
| |
| if (dx > 0) |
| { |
| src.x = XDPTOLP(dc, rc->left); |
| dest.x = XDPTOLP(dc, rc->left + abs(dx)); |
| } |
| else |
| { |
| src.x = XDPTOLP(dc, rc->left + abs(dx)); |
| dest.x = XDPTOLP(dc, rc->left); |
| } |
| if (dy > 0) |
| { |
| src.y = YDPTOLP(dc, rc->top); |
| dest.y = YDPTOLP(dc, rc->top + abs(dy)); |
| } |
| else |
| { |
| src.y = YDPTOLP(dc, rc->top + abs(dy)); |
| dest.y = YDPTOLP(dc, rc->top); |
| } |
| |
| width = rc->right - rc->left - abs(dx); |
| height = rc->bottom - rc->top - abs(dy); |
| |
| if (!BitBlt(hdc, dest.x, dest.y, width, height, hdc, src.x, src.y, |
| SRCCOPY)) |
| return FALSE; |
| |
| if (hrgnUpdate) |
| { |
| if (dx > 0) |
| hrgn1 = CreateRectRgn(rc->left, rc->top, rc->left+dx, rc->bottom); |
| else if (dx < 0) |
| hrgn1 = CreateRectRgn(rc->right+dx, rc->top, rc->right, |
| rc->bottom); |
| else |
| hrgn1 = CreateRectRgn(0, 0, 0, 0); |
| |
| if (dy > 0) |
| hrgn2 = CreateRectRgn(rc->left, rc->top, rc->right, rc->top+dy); |
| else if (dy < 0) |
| hrgn2 = CreateRectRgn(rc->left, rc->bottom+dy, rc->right, |
| rc->bottom); |
| else |
| hrgn2 = CreateRectRgn(0, 0, 0, 0); |
| |
| RgnType = CombineRgn(hrgnUpdate, hrgn1, hrgn2, RGN_OR); |
| DeleteObject(hrgn1); |
| DeleteObject(hrgn2); |
| } |
| |
| if (rcUpdate) GetRgnBox( hrgnUpdate, rcUpdate ); |
| return TRUE; |
| } |
| |
| |
| /************************************************************************* |
| * ScrollWindowEx (USER.319) |
| * |
| * FIXME: broken |
| * |
| * SCROLL_TraceChildren can help |
| */ |
| |
| int ScrollWindowEx(HWND hwnd, short dx, short dy, LPRECT rect, LPRECT clipRect, |
| HRGN hrgnUpdate, LPRECT rcUpdate, WORD flags) |
| { |
| HDC hdc; |
| RECT rc, cliprc; |
| |
| dprintf_scroll(stddeb,"ScrollWindowEx: dx=%d, dy=%d, wFlags=%04x\n",dx, dy, flags); |
| |
| hdc = GetDC(hwnd); |
| |
| if (rect == NULL) |
| GetClientRect(hwnd, &rc); |
| else |
| CopyRect(&rc, rect); |
| if (clipRect == NULL) |
| GetClientRect(hwnd, &cliprc); |
| else |
| CopyRect(&cliprc, clipRect); |
| |
| ScrollDC(hdc, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate); |
| |
| if (flags | SW_INVALIDATE) |
| { |
| RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | |
| ((flags & SW_ERASE) ? RDW_ERASENOW : 0)); |
| } |
| |
| ReleaseDC(hwnd, hdc); |
| return RgnType; |
| } |