mattias преди 4 месеца
родител
ревизия
7d47aee3e6
променени са 5 файла, в които са добавени 186 реда и са изтрити 85 реда
  1. 74 54
      demo/ScrollBox/MainUnit.lfm
  2. 47 4
      demo/ScrollBox/MainUnit.pas
  3. 1 0
      demo/democomps/fresnel.democheckbox.pas
  4. 27 10
      src/base/fresnel.dom.pas
  5. 37 17
      src/base/fresnel.renderer.pas

+ 74 - 54
demo/ScrollBox/MainUnit.lfm

@@ -33,62 +33,82 @@ object MainForm: TMainForm
         Style = 'width: 50px; height: 50px; margin: 8px; border: 2px solid black;'
       end
     end
+    object OverflowXDiv: TDiv
+      Style = 'min-width: 50px; min-height: 50px; margin: 6px; border: 1px solid black; border-radius: 5px; padding: 6px;'
+      object OverflowXLabel: TLabel
+        Caption = 'overflow-x'
+        Style = 'margin: 6px; font-weight: bold; font-size: 1.2em; '
+      end
+      object OverflowXVisible: TDemoRadioButton
+        Caption = 'visible'
+        OnClick = OnOverflowXClicked
+      end
+      object OverflowXHidden: TDemoRadioButton
+        Caption = 'hidden'
+        OnClick = OnOverflowXClicked
+      end
+      object OverflowXClip: TDemoRadioButton
+        Caption = 'clip'
+        OnClick = OnOverflowXClicked
+      end
+      object OverflowXScroll: TDemoRadioButton
+        Caption = 'scroll'
+        OnClick = OnOverflowXClicked
+      end
+      object OverflowXAuto: TDemoRadioButton
+        Caption = 'auto'
+        OnClick = OnOverflowXClicked
+      end
+    end
+    object OverflowYDiv: TDiv
+      Style = 'min-width: 50px; min-height: 50px; margin: 6px; border: 1px solid black; border-radius: 5px; padding: 6px;'
+      object OverflowYLabel: TLabel
+        Caption = 'overflow-y'
+        Style = 'margin: 6px; font-weight: bold; font-size: 1.2em; '
+        OnClick = OnOverflowYClicked
+      end
+      object OverflowYVisible: TDemoRadioButton
+        Caption = 'visible'
+        OnClick = OnOverflowYClicked
+      end
+      object OverflowYHidden: TDemoRadioButton
+        Caption = 'hidden'
+        OnClick = OnOverflowYClicked
+      end
+      object OverflowYClip: TDemoRadioButton
+        Caption = 'clip'
+        OnClick = OnOverflowYClicked
+      end
+      object OverflowYScroll: TDemoRadioButton
+        Caption = 'scroll'
+        OnClick = OnOverflowYClicked
+      end
+      object OverflowYAuto: TDemoRadioButton
+        Caption = 'auto'
+        OnClick = OnOverflowYClicked
+      end
+    end
     object OptionsDiv: TDiv
       Style = 'min-width: 50px; min-height: 50px; margin: 6px; border: 1px solid black; border-radius: 5px; '
-      object OverflowXDiv: TDiv
-        Style = 'min-width: 50px; min-height: 50px; margin: 6px; border: 1px solid black; padding: 6px;'
-        object OverflowXLabel: TLabel
-          Caption = 'overflow-x'
-          Style = 'margin: 6px; font-weight: bold; font-size: 1.2em; '
-        end
-        object OverflowXVisible: TDemoRadioButton
-          Caption = 'visible'
-          OnClick = OnOverflowXClicked
-        end
-        object OverflowXHidden: TDemoRadioButton
-          Caption = 'hidden'
-          OnClick = OnOverflowXClicked
-        end
-        object OverflowXClip: TDemoRadioButton
-          Caption = 'clip'
-          OnClick = OnOverflowXClicked
-        end
-        object OverflowXScroll: TDemoRadioButton
-          Caption = 'scroll'
-          OnClick = OnOverflowXClicked
-        end
-        object OverflowXAuto: TDemoRadioButton
-          Caption = 'auto'
-          OnClick = OnOverflowXClicked
-        end
-      end
-      object OverflowYDiv: TDiv
-        Style = 'min-width: 50px; min-height: 50px; margin: 6px; border: 1px solid black; padding: 6px;'
-        object OverflowYLabel: TLabel
-          Caption = 'overflow-y'
-          Style = 'margin: 6px; font-weight: bold; font-size: 1.2em; '
-          OnClick = OnOverflowYClicked
-        end
-        object OverflowYVisible: TDemoRadioButton
-          Caption = 'visible'
-          OnClick = OnOverflowYClicked
-        end
-        object OverflowYHidden: TDemoRadioButton
-          Caption = 'hidden'
-          OnClick = OnOverflowYClicked
-        end
-        object OverflowYClip: TDemoRadioButton
-          Caption = 'clip'
-          OnClick = OnOverflowYClicked
-        end
-        object OverflowYScroll: TDemoRadioButton
-          Caption = 'scroll'
-          OnClick = OnOverflowYClicked
-        end
-        object OverflowYAuto: TDemoRadioButton
-          Caption = 'auto'
-          OnClick = OnOverflowYClicked
-        end
+      object AutoHideCheckBox: TDemoCheckBox
+        Style = 'margin: 6px;'
+        Caption = 'Auto Hide'
+        OnClick = OnAutoHideClicked
+      end
+      object OverlayCheckBox: TDemoCheckBox
+        Style = 'margin: 6px;'
+        Caption = 'Overlay'
+        OnClick = OnOverlayClicked
+      end
+      object ThinCheckBox: TDemoCheckBox
+        Style = 'margin: 6px;'
+        Caption = 'Thin (scrollbar-width)'
+        OnClick = OnThinClicked
+      end
+      object RTLCheckBox: TDemoCheckBox
+        Style = 'margin: 6px;'
+        Caption = 'RTL (direction)'
+        OnClick = OnRTLClicked
       end
     end
   end

+ 47 - 4
demo/ScrollBox/MainUnit.pas

@@ -6,7 +6,7 @@ interface
 
 uses
   Classes, SysUtils, Fresnel.Forms, Fresnel.Controls, Fresnel.Events,
-  FCL.Events, Fresnel.DemoRadioButton;
+  FCL.Events, Fresnel.DemoRadioButton, Fresnel.DemoCheckbox;
 
 type
 
@@ -34,9 +34,17 @@ type
     OverflowYClip: TDemoRadioButton;
     OverflowYScroll: TDemoRadioButton;
     OverflowYAuto: TDemoRadioButton;
+    AutoHideCheckBox: TDemoCheckBox;
+    OverlayCheckBox: TDemoCheckBox;
+    ThinCheckBox: TDemoCheckBox;
+    RTLCheckBox: TDemoCheckBox;
     procedure MainFormCreate(Sender: TObject);
+    procedure OnAutoHideClicked(Event : TAbstractEvent);
     procedure OnOverflowXClicked(Event : TAbstractEvent);
     procedure OnOverflowYClicked(Event : TAbstractEvent);
+    procedure OnOverlayClicked(Event : TAbstractEvent);
+    procedure OnThinClicked(Event : TAbstractEvent);
+    procedure OnRTLClicked(Event : TAbstractEvent);
   private
   public
   end;
@@ -52,12 +60,26 @@ implementation
 
 procedure TMainForm.MainFormCreate(Sender: TObject);
 begin
+  Label1.Caption:='Fresnel is a visual component library based on CSS and custom drawn components.';
+
   ScrollDiv1.Style:='overflow: auto; width: 200px; height: 50px;';
   OverflowXAuto.Checked:=true;
   OverflowYAuto.Checked:=true;
 
+  OverlayCheckBox.Checked:=ScrollbarsOverlay;
+  AutoHideCheckBox.Checked:=ScrollbarsAutoHide;
 
-  Label1.Caption:='Fresnel is a visual component library based on CSS and custom drawn components.';
+  // todo: step buttons
+  // todo: stable
+  // todo: both edges
+  // todo: css color
+  // todo: default thumb+track color, hover/not hover
+  // todo: rtl
+end;
+
+procedure TMainForm.OnAutoHideClicked(Event: TAbstractEvent);
+begin
+  ScrollbarsAutoHide:=AutoHideCheckBox.Checked;
 end;
 
 procedure TMainForm.OnOverflowXClicked(Event: TAbstractEvent);
@@ -65,7 +87,7 @@ var
   El: TDemoRadioButton;
 begin
   El:=Event.Sender as TDemoRadioButton;
-  writeln('TMainForm.OnOverflowXClicked ',El.Caption);
+  //writeln('TMainForm.OnOverflowXClicked ',El.Caption);
   ScrollDiv1.SetStyleAttr('overflow-x',El.Caption);
 end;
 
@@ -74,9 +96,30 @@ var
   El: TDemoRadioButton;
 begin
   El:=Event.Sender as TDemoRadioButton;
-  writeln('TMainForm.OnOverflowYClicked ',El.Caption);
+  //writeln('TMainForm.OnOverflowYClicked ',El.Caption);
   ScrollDiv1.SetStyleAttr('overflow-y',El.Caption);
 end;
 
+procedure TMainForm.OnOverlayClicked(Event: TAbstractEvent);
+begin
+  ScrollbarsOverlay:=OverlayCheckBox.Checked;
+end;
+
+procedure TMainForm.OnThinClicked(Event: TAbstractEvent);
+begin
+  if ThinCheckBox.Checked then
+    ScrollDiv1.SetStyleAttr('scrollbar-width','thin')
+  else
+    ScrollDiv1.SetStyleAttr('scrollbar-width','');
+end;
+
+procedure TMainForm.OnRTLClicked(Event: TAbstractEvent);
+begin
+  if RTLCheckBox.Checked then
+    ScrollDiv1.SetStyleAttr('direction','rtl')
+  else
+    ScrollDiv1.SetStyleAttr('direction','');
+end;
+
 end.
 

+ 1 - 0
demo/democomps/fresnel.democheckbox.pas

@@ -68,6 +68,7 @@ type
     CaptionLabel: TLabel;
     constructor Create(AOwner: TComponent); override;
     class function GetCSSTypeStyle: TCSSString; override;
+  published
     property Caption: TFresnelCaption read GetCaption write SetCaption;
     property Checked: boolean read GetChecked write SetChecked;
     property OnChange: TNotifyEvent read FOnChange write FOnChange;

+ 27 - 10
src/base/fresnel.dom.pas

@@ -1663,7 +1663,8 @@ type
     FHeight: TFresnelLength;
     FLayouter: TFresnelLayouter;
     FOnDomChanged: TNotifyEvent;
-    FScrollbarOverlay: boolean;
+    FScrollbarsAutoHide: boolean;
+    FScrollbarsOverlay: boolean;
     FScrollbarThinWidth: array[boolean] of TFresnelLength;
     FScrollbarWidth: array[boolean] of TFresnelLength;
     FStylesheet: TStrings;
@@ -1673,6 +1674,7 @@ type
     procedure CSSResolverLog(Sender: TObject; Entry: TCSSResolverLogEntry);
     function GetFocusedElement: TFresnelElement;
     procedure SetFocusedElement(const aValue: TFresnelElement);
+    procedure SetScrollbarsAutoHide(AValue: boolean);
   protected
     class var FFresnelEventsRegistered: boolean;
   protected
@@ -1682,7 +1684,6 @@ type
     procedure DispatchPointerCapture(El: TFresnelElement; Lost: boolean; const aPointerId: TFreHandle); virtual;
     function GetDPI(IsHorizontal: boolean): TFresnelLength; override;
     function GetHeight: TFresnelLength; virtual;
-    function GetScrollbarsOverlay: boolean; virtual;
     function GetScrollbarsThinWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetScrollbarsWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetVPLength(l: TFresnelViewportLength): TFresnelLength; virtual;
@@ -1789,6 +1790,7 @@ type
     function ViewportToPaddingBox(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; overload; // viewport to padding-box coord of El
     function ViewportToPaddingBox(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; overload; // viewport to padding-box coord of El
     function GetPointerCaptureEl(const aPointerId: TFreHandle): TFresnelElement;
+    function GetFirstPointerCaptureEl(El: TFresnelElement): TFreHandle;
     procedure SetPointerCapture(const aPointerId: TFreHandle); override; overload;
     procedure SetPointerCapture(El: TFresnelElement; const aPointerId: TFreHandle); virtual; overload;
     procedure ReleasePointerCapture(const aPointerId: TFreHandle); override; overload;
@@ -1800,7 +1802,8 @@ type
     function WSInput(WSData: TFresnelInputEventInit) : boolean; virtual;
     property VPApplication: IFresnelVPApplication read FVPApplication;
     property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
-    property ScrollbarsOverlay: boolean read GetScrollbarsOverlay write SetScrollbarsOverlay;
+    property ScrollbarsAutoHide: boolean read FScrollbarsAutoHide write SetScrollbarsAutoHide;
+    property ScrollbarsOverlay: boolean read FScrollbarsOverlay write SetScrollbarsOverlay;
     property ScrollbarsWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsWidth write SetScrollbarsWidth;
     property ScrollbarsThinWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsThinWidth write SetScrollbarsThinWidth;
     property VPLength[l: TFresnelViewportLength]: TFresnelLength read GetVPLength write SetVPLength;
@@ -6673,6 +6676,13 @@ begin
   TrySetFocusControl(aValue);
 end;
 
+procedure TFresnelViewport.SetScrollbarsAutoHide(AValue: boolean);
+begin
+  if FScrollbarsAutoHide=AValue then Exit;
+  FScrollbarsAutoHide:=AValue;
+  Invalidate;
+end;
+
 function TFresnelViewport.GetDPI(IsHorizontal: boolean): TFresnelLength;
 begin
   Result:=FDPI[IsHorizontal];
@@ -6694,11 +6704,6 @@ begin
   Result:=FHeight;
 end;
 
-function TFresnelViewport.GetScrollbarsOverlay: boolean;
-begin
-  Result:=FScrollbarOverlay;
-end;
-
 function TFresnelViewport.GetVPLength(l: TFresnelViewportLength
   ): TFresnelLength;
 begin
@@ -6868,8 +6873,8 @@ end;
 
 procedure TFresnelViewport.SetScrollbarsOverlay(const AValue: boolean);
 begin
-  if FScrollbarOverlay=AValue then exit;
-  FScrollbarOverlay:=AValue;
+  if FScrollbarsOverlay=AValue then exit;
+  FScrollbarsOverlay:=AValue;
   DomChanged;
 end;
 
@@ -7248,6 +7253,18 @@ begin
   Result:=nil;
 end;
 
+function TFresnelViewport.GetFirstPointerCaptureEl(El: TFresnelElement
+  ): TFreHandle;
+var
+  i: Integer;
+begin
+  if El=nil then exit(nil);
+  for i:=0 to length(FPointerCaptures)-1 do
+    if FPointerCaptures[i].Element=El then
+      exit(FPointerCaptures[i].Id);
+  Result:=nil;
+end;
+
 procedure TFresnelViewport.SetPointerCapture(const aPointerId: TFreHandle);
 begin
   // must be implemented by descendant

+ 37 - 17
src/base/fresnel.renderer.pas

@@ -725,25 +725,27 @@ var
   r, aPaddingBox: TFresnelRect;
   aScrollbar: TRendererScrollBar;
   IsLeft, HasVertBar, HasHorzBar: Boolean;
+  VP: TFresnelViewport;
 begin
   LNode:=TUsedLayoutNode(El.LayoutNode);
   HasVertBar:=flfScrollbarVertical in LNode.Flags;
   HasHorzBar:=flfScrollbarHorizontal in LNode.Flags;
   if (not HasVertBar) and (not HasHorzBar) then exit;
 
+  VP:=El.Viewport;
   if HasVertBar then
   begin
     case LNode.ScrollbarWidth of
-    CSSRegistry.kwThin: BarWidth:=El.Viewport.ScrollbarsThinWidth[false];
-    else BarWidth:=El.Viewport.ScrollbarsWidth[false];
+    CSSRegistry.kwThin: BarWidth:=VP.ScrollbarsThinWidth[false];
+    else BarWidth:=VP.ScrollbarsWidth[false];
     end;
     IsLeft:=El.ComputedDirection=CSSRegistry.kwRTL;
   end else
     IsLeft:=false;
   if HasHorzBar then
     case LNode.ScrollbarWidth of
-    CSSRegistry.kwThin: BarHeight:=El.Viewport.ScrollbarsThinWidth[true];
-    else BarHeight:=El.Viewport.ScrollbarsWidth[true];
+    CSSRegistry.kwThin: BarHeight:=VP.ScrollbarsThinWidth[true];
+    else BarHeight:=VP.ScrollbarsWidth[true];
     end;
   aPaddingBox:=El.GetUsedPaddingBox;
   //writeln('TFresnelRenderer.DrawScrollBars ',El.Name,' PaddingBox=',aPaddingBox.ToString);
@@ -773,7 +775,6 @@ begin
       {$IFDEF VerboseFresnelScrolling}
       writeln('TFresnelRenderer.DrawScrollBars ',El.Name,' Vertical ScrollHeight=',FloatToCSSStr(El.ScrollHeight),' ClientHeight=',FloatToCSSStr(El.ClientHeight),' ScrollTop=',FloatToCSSStr(El.ScrollTop)+' BarWidth='+FloatToCSSStr(BarWidth)+' r='+r.ToString);
       {$ENDIF}
-      aScrollbar.Draw(Self);
     end;
   end else if aScrollbar<>nil then
     aScrollbar.Free;
@@ -808,25 +809,44 @@ begin
       {$IFDEF VerboseFresnelScrolling}
       writeln('TFresnelRenderer.DrawScrollBars ',El.Name,' Horizontal ScrollWidth=',FloatToCSSStr(El.ScrollWidth),' ClientWidth=',FloatToCSSStr(El.ClientWidth),' ScrollLeft=',FloatToCSSStr(El.ScrollLeft)+' BarHeight='+FloatToCSSStr(BarHeight)+' r='+r.ToString);
       {$ENDIF}
-      aScrollbar.Draw(Self);
     end;
   end else if aScrollbar<>nil then
     aScrollbar.Free;
 
-  if HasVertBar and HasHorzBar then
+  if HasVertBar or HasHorzBar then
   begin
-    r.Bottom:=aPaddingBox.Bottom;
-    r.Top:=Max(aPaddingBox.Top,r.Bottom-BarHeight);
-    if IsLeft then
+    if VP.ScrollbarsAutoHide
+        and not El.IsHovered
+        and (VP.GetFirstPointerCaptureEl(El.ScrollBarHorizontal)=nil)
+        and (VP.GetFirstPointerCaptureEl(El.ScrollBarVertical)=nil)
+        and (VP.GetFirstPointerCaptureEl(El)=nil)
+    then
+      exit;
+    if HasHorzBar then
     begin
-      r.Left:=aPaddingBox.Left;
-      r.Right:=Min(aPaddingBox.Right,r.Left+BarWidth);
-    end else begin
-      r.Right:=aPaddingBox.Right;
-      r.Left:=Max(aPaddingBox.Left,r.Right-BarWidth);
+      aScrollbar:=TRendererScrollBar(El.ScrollBarHorizontal);
+      aScrollbar.Draw(Self);
+    end;
+    if HasVertBar then
+    begin
+      aScrollbar:=TRendererScrollBar(El.ScrollBarVertical);
+      aScrollbar.Draw(Self);
+    end;
+    if HasVertBar and HasHorzBar then
+    begin
+      r.Bottom:=aPaddingBox.Bottom;
+      r.Top:=Max(aPaddingBox.Top,r.Bottom-BarHeight);
+      if IsLeft then
+      begin
+        r.Left:=aPaddingBox.Left;
+        r.Right:=Min(aPaddingBox.Right,r.Left+BarWidth);
+      end else begin
+        r.Right:=aPaddingBox.Right;
+        r.Left:=Max(aPaddingBox.Left,r.Right-BarWidth);
+      end;
+      if not r.IsEmpty then
+        aScrollbar.DrawCorner(Self,r);
     end;
-    if not r.IsEmpty then
-      aScrollbar.DrawCorner(Self,r);
   end;
 end;