From b46ea85bc3b5eaa4c7b6706a07e82cde39395974 Mon Sep 17 00:00:00 2001 From: martin Date: Sun, 22 Jan 2012 18:12:29 +0000 Subject: [PATCH] GTK2 ScrollWindowEx git-svn-id: trunk@34872 - --- lcl/interfaces/gtk2/gtk2winapi.inc | 107 +++++++++++++++++++---------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/lcl/interfaces/gtk2/gtk2winapi.inc b/lcl/interfaces/gtk2/gtk2winapi.inc index 0ab9fcc40a..de2405452b 100644 --- a/lcl/interfaces/gtk2/gtk2winapi.inc +++ b/lcl/interfaces/gtk2/gtk2winapi.inc @@ -7386,8 +7386,9 @@ var Window: PGdkWindow; {$ifdef GTK_2_8} Region: PGdkRegion; - Rect1: TGdkRectangle; - Rect2: TRect; + Rect1: TGdkRectangle; // full source rect + Rect1a: TGdkRectangle; // source rect for clip + Rect2: TRect; // area to invalidate WidgetInfo: PWidgetInfo; {$ENDIF} begin @@ -7410,50 +7411,84 @@ begin Rect1.Y := 0; //Widget^.Allocation.Y; Rect1.width := Widget^.Allocation.Width; Rect1.height := Widget^.Allocation.Height; - - WidgetInfo := GetWidgetInfo(Widget, False); - if WidgetInfo <> nil then begin - if (dy < 0) then begin - if (WidgetInfo^.UpdateRect.Bottom > 0) then - Rect1.Height := Min(Rect1.height, WidgetInfo^.UpdateRect.Top); - Rect2 := Rect(0, Rect1.height + dy, Rect1.width, Widget^.Allocation.Height); - end; - if dy > 0 then begin - Rect1.y := Max(Rect1.y, WidgetInfo^.UpdateRect.Bottom); - Rect2 := Rect(0, 0, Rect1.width, Rect1.y + dy); - end; - end; + DebugLn(['ScrollWindowEx A ', dbgs(Rect1),' dy=',dy, ' scroll=',dbgs(prcScroll^), ' clip=',dbgs(prcClip^)]); if PrcScroll <> nil then begin - Rect1.x := PrcScroll^.Left; - Rect1.y := PrcScroll^.Top; - Rect1.width := PrcScroll^.Right - PrcScroll^.Left; - Rect1.height := PrcScroll^.Bottom - PrcScroll^.Top; - if (PrcClip <> nil) and EqualRect(PrcClip^, PrcScroll^) then - // do nothing - else - begin - Region := gdk_region_rectangle(@Rect1); - gdk_window_move_region(Window, Region, dx, dy); + Rect1.x := Max(Rect1.x, PrcScroll^.Left); + Rect1.y := Max(Rect1.y, PrcScroll^.Top); + Rect1.width := Min(Rect1.width - Rect1.x, PrcScroll^.Right - PrcScroll^.Left); + //Rect1.width := Min(Rect1.width - (Rect1.x - Widget^.Allocation.X), PrcScroll^.Right - PrcScroll^.Left); + Rect1.height := Min(Rect1.height - Rect1.y, PrcScroll^.Bottom - PrcScroll^.Top); + end; + if (PrcClip <> nil) then begin + // Limit the source rect, so it will fit into PrcClip + Rect1a.x := Max(PrcClip^.Left - dx, Rect1.x); + Rect1a.y := Max(PrcClip^.Top - dy, Rect1.y); + Rect1a.width := Min(PrcClip^.Right - dx - Rect1.x, Rect1.width); + Rect1a.height := Min(PrcClip^.Bottom - dy - Rect1.y, Rect1.height); + end + else + Rect1a := Rect1; + DebugLn(['ScrollWindowEx B ', dbgs(Rect1), ' ', dbgs(Rect1a)]); + + WidgetInfo := GetWidgetInfo(Widget, False); + if WidgetInfo <> nil then begin + DebugLn(['ScrollWindowEx C ', dbgs(WidgetInfo^.UpdateRect)]); + // exclude allready invalidated area + if (WidgetInfo^.UpdateRect.Right >= Rect1a.x + Rect1a.width) and + (WidgetInfo^.UpdateRect.Left <= Rect1a.x) + then begin + if (dy < 0) and (WidgetInfo^.UpdateRect.Bottom > 0) then + Rect1a.Height := Min(Rect1a.y + Rect1a.height, + WidgetInfo^.UpdateRect.Top) - Rect1a.y; + if (dy > 0) and (Rect1a.y < WidgetInfo^.UpdateRect.Bottom) then begin + Rect1a.height := Rect1a.height - (WidgetInfo^.UpdateRect.Bottom - Rect1a.y); + Rect1a.y := WidgetInfo^.UpdateRect.Bottom; + end; end; - end else - begin - Region := gdk_region_rectangle(@Rect1); + // TODO: content moved into currently invalidated space, may reduce the inval rect + + if (WidgetInfo^.UpdateRect.Bottom >= Rect1a.y + Rect1a.height) and + (WidgetInfo^.UpdateRect.Top <= Rect1a.y) + then begin + if (dx < 0) and (WidgetInfo^.UpdateRect.Right > 0) then + Rect1a.width := Min(Rect1a.x + Rect1a.width, + WidgetInfo^.UpdateRect.Left) - Rect1a.x; + if (dx > 0) and (Rect1a.x < WidgetInfo^.UpdateRect.Right) then begin + Rect1a.width := Rect1a.width - (WidgetInfo^.UpdateRect.Right - Rect1a.x); + Rect1a.x := WidgetInfo^.UpdateRect.Right; + end; + end; + end; + DebugLn(['ScrollWindowEx D ', dbgs(Rect1a)]); + + + if (Rect1a.height > 0) and (Rect1a.width > 0) then begin + // Calculate area to invalidate + // Rect1a.y may either be equal or greater than Rect1.y + // Rect1a.height may either be equal or less than Rect1.height + if (dy < 0) then + Rect2 := Rect(Rect1.x, Rect1a.y + Rect1a.height + dy, + Rect1.width, Rect1.y + Rect1.height); + if dy > 0 then + Rect2 := Rect(Rect1.x, Rect1.y, + Rect1.width, Rect1a.y + dy); + // Todo dx + DebugLn(['ScrollWindowEx E ', dbgs(Rect2)]); + + Region := gdk_region_rectangle(@Rect1a); gdk_window_move_region(Window, Region, dx, dy); + end + else begin + // invalidate, nothing to scroll + Rect2 := Rect(Rect1.x, Rect1.y, Rect1.x + Rect1.width, Rect1.y + Rect1.height); + DebugLn(['ScrollWindowEx F ', dbgs(Rect2)]); end; // Rect2 includes the Area at the scroll-in side of Rect1 // gdk_window_move_region is supposed to have invalidated it, but some // implementations seem not to do this. (bug 14297) - if (prcScroll <> nil) then - begin - if prcClip <> nil then - Rect1 := GdkRectFromRect(prcClip^) - else - Rect1 := GdkRectFromRect(prcScroll^); - gtk_widget_draw(Widget, @Rect1); - end else if (dy <> 0) then InvalidateRect(hWnd, @Rect2, false); {$ELSE}