Browse Source

ProgressBar Added Marquee Bounce and Stepit Method,TimerPlayPause works also for Marquee (useful for debugging)

ProgressBar Added Marquee Bounce and Stepit Method,TimerPlayPause works also for Marquee (useful for debugging)
Massimo Magnano 11 months ago
parent
commit
aa33f65d79
3 changed files with 217 additions and 81 deletions
  1. 102 28
      bgraflashprogressbar.pas
  2. 97 52
      test/test_progressbar/umain.lfm
  3. 18 1
      test/test_progressbar/umain.pas

+ 102 - 28
bgraflashprogressbar.pas

@@ -18,6 +18,8 @@
              Deleted Unit BGRADrawerFlashProgressBar;
              New Test with all Features
              Added Timer Style
+    2025-01  Added Marquee Bounce and Stepit Method,
+             TimerPlayPause works also for Marquee (useful for debugging)
 ***************************** END CONTRIBUTOR(S) *****************************}
 unit BGRAFlashProgressBar;
 
@@ -78,7 +80,11 @@ type
     xpos: integer;
     internalTimer: TFPTimer;
     marqueeLeft,
-    marqueeRight: Integer;
+    marqueeRight,
+    marqueeCount,
+    marqueeBCount: Integer;
+    marqueeWall,
+    marqueeBouncing: Boolean;
 
     procedure SetBackgroundRandomize(AValue: boolean);
     procedure SetBackgroundRandomizeMaxIntensity(AValue: word);
@@ -130,8 +136,14 @@ type
 
     procedure Draw(ABitmap: TBGRABitmap);
 
-    //Timer Methods applies only if Style is pbstTimer
+    //Step It, if Style is pbstNormal then Inc/Dec Value,
+    //         if pbstMarquee then do next Animation Step (AIncrement is ignored)
+    //         if pbstTimer then Value is decremented of 100ms (AIncrement is ignored)
+    procedure StepIt(AIncrement: Double);
+
+    //Timer Restart applies only if Style is pbstTimer
     procedure TimerReStart;
+    //Timer Paly/Pause applies only if Style is pbstMarquee or pbstTimer
     procedure TimerPlayPause;
 
     property XPosition: integer read xpos;
@@ -164,8 +176,6 @@ type
     property MarqueeWidth: Word read FMarqueeWidth write SetMarqueeWidth default 0;
     property MarqueeSpeed: TBGRAPBarMarqueeSpeed read FMarqueeSpeed write SetMarqueeSpeed default pbmsMedium;
     property MarqueeDirection: TBGRAPBarMarqueeDirection read FMarqueeDirection write SetMarqueeDirection default pbmdToRight;
-
-    { #todo 5 -oMaxM : I'm implementing this in the new year }
     property MarqueeBounce: Word read FMarqueeBounce write SetMarqueeBounce;
 
     property TimerInterval: Cardinal read FTimerInterval write SetTimerInterval default 100;
@@ -312,6 +322,7 @@ end;
 
 procedure TBGRAFlashProgressBar.SetMarqueeBounce(AValue: Word);
 begin
+  marqueeBCount:= AValue;
   if FMarqueeBounce=AValue then Exit;
   FMarqueeBounce:=AValue;
 
@@ -395,9 +406,13 @@ begin
     Case FStyle of
       pbstMarquee: begin
         SetMarqueeSpeed(FMarqueeSpeed);
-        marqueeLeft:= 0;
 
-        if not(csLoading in ComponentState) and
+        if (FMarqueeDirection = pbmdToRight)
+        then marqueeLeft:= 2
+        else marqueeLeft:= -FMarqueeWidth;
+
+        if FTimerAutoRestart and
+           not(csLoading in ComponentState) and
            not(csDesigning in ComponentState) then internalTimer.Enabled:= True;
       end;
       pbstTimer: begin
@@ -455,12 +470,40 @@ procedure TBGRAFlashProgressBar.TimerOnTimer(Sender: TObject);
 begin
   Case FStyle of
     pbstMarquee: begin
+      if (FMarqueeBounce > 0) then
+      begin
+        if marqueeBouncing then
+        begin
+          if (marqueeCount = 0) //we've reached the rebound wall
+          then begin
+                 marqueeCount:= 3; //Set the bounce length (3*2pixels)
+
+                 if (marqueeCurMode = pbmdToRight)
+                 then marqueeCurMode:= pbmdToLeft
+                 else marqueeCurMode:= pbmdToRight;
+
+                 //decreases the rebound counter only if we are in the real wall
+                 if marqueeWall then dec(marqueeBCount);
+
+                 if (marqueeBCount > 0)
+                 then marqueeBouncing:= True
+                 else begin
+                        //Stop Bouncing
+                        if marqueeWall then marqueeBCount:= FMarqueeBounce;
+                        marqueeBouncing:= False;
+                      end;
+               end
+          else dec(marqueeCount);
+        end;
+      end;
+
+      //Move the bar 2 pixels
       if (marqueeCurMode = pbmdToRight)
       then inc(marqueeLeft, 2)
       else dec(marqueeLeft, 2);
     end;
     pbstTimer: begin
-      //FValue:= TTime(, FTimerInterval);
+      { #note -oMaxM : If we had to be more precise we should keep the Start time and subtract the current time }
       FValue:= IncMilliSecond(FValue, -internalTimer.Interval);
       if (FValue <= 0)
       then begin
@@ -511,13 +554,19 @@ begin
   inherited Loaded;
 
   Case FStyle of
-    pbstMarquee: if not(csDesigning in ComponentState) then internalTimer.Enabled:= True;
+    pbstMarquee: begin
+      if (FMarqueeDirection = pbmdToRight)
+      then marqueeLeft:= 2
+      else marqueeLeft:= -FMarqueeWidth;
+
+      if FTimerAutoRestart and not(csDesigning in ComponentState) then internalTimer.Enabled:= True;
+    end;
     pbstTimer: begin
-                 FValue:= FMaxValue;
-                 internalTimer.Interval:= FTimerInterval;
+      FValue:= FMaxValue;
+      internalTimer.Interval:= FTimerInterval;
 
-                 if FTimerAutoRestart and not(csDesigning in ComponentState) then internalTimer.Enabled:= True;
-               end;
+      if FTimerAutoRestart and not(csDesigning in ComponentState) then internalTimer.Enabled:= True;
+    end;
     else internalTimer.Enabled:= False;
   end;
 end;
@@ -573,6 +622,7 @@ begin
   marqueeCurMode:= pbmdToRight;
   marqueeLeft:= 0;
   marqueeRight:= 0;
+  marqueeBouncing:= False;
 
   //Timer
   FTimerInterval:= 100;
@@ -791,26 +841,31 @@ begin
         if (marqueeCurMode = pbmdToRight)
         then begin
                //check if the whole bar is out put it back to the beginning
-               if (marqueeLeft >= tx-2) then
-               begin
-                 marqueeLeft:= 2;
-               end;
+               if (marqueeLeft >= content.Right) then marqueeLeft:= content.Left;
 
                //Calculate the Right
                marqueeRight:= marqueeLeft+(rMarqueeWidth-1);
 
                //Check if part of the bar is out calculate the visible piece on the left
                marqueeOver:= 0;
-               if (marqueeRight > tx-2) then
+               marqueeWall:= (marqueeRight >= content.Right-1);
+               if marqueeWall then
                begin
-                 marqueeOver:= marqueeRight-(tx-2);
+                 if (FMarqueeBounce > 0)
+                 then begin
+                        //Put perfectly on the Right edge
+                        marqueeRight:= content.Right-1;
+                        marqueeLeft:= marqueeRight-(rMarqueeWidth-1);
+                        marqueeBouncing:= True;
+                      end
+                 else marqueeOver:= marqueeRight-(content.Right-1);
                end;
              end
         else begin
                //check if the whole bar is out put it back to the end
-               if (marqueeLeft <= -(rMarqueeWidth+2)) then
+               if (marqueeLeft <= -rMarqueeWidth) then //(rMarqueeWidth+2)) then
                begin
-                 marqueeLeft:= tx-2-rMarqueeWidth;
+                 marqueeLeft:= content.Right-rMarqueeWidth;
                end;
 
                //Calculate the Right
@@ -818,9 +873,17 @@ begin
 
                //check if part of the bar is out then the visible piece on the left is equal to marqueeRight
                marqueeOver:= 0;
-               if (marqueeRight < rMarqueeWidth) then
+               marqueeWall:= (marqueeRight-1 <= rMarqueeWidth);
+               if marqueeWall then
                begin
-                 marqueeOver:= marqueeRight;
+                 if (FMarqueeBounce > 0)
+                 then begin
+                        //Put perfectly on the Left edge
+                        marqueeLeft:= content.Left;
+                        marqueeRight:= marqueeLeft+(rMarqueeWidth-1);
+                        marqueeBouncing:= True;
+                      end
+                 else marqueeOver:= marqueeRight;
                end;
              end;
 
@@ -835,15 +898,14 @@ begin
              end
         else begin
                //Draw visible piece on the Left
-               DrawBar(rect(2, content.top, marqueeOver, content.bottom), FBarColor);
+               DrawBar(rect(content.Left, content.top, marqueeOver, content.bottom), FBarColor);
                ABitmap.SetPixel(marqueeOver, content.top, BGRA(62, 62, 62));
                ABitmap.SetVertLine(marqueeOver, content.top + 1, content.bottom - 1, BGRA(40, 40, 40));
                //Draw visible piece on the Right
-               DrawBar(rect(tx-2-(rMarqueeWidth+1-marqueeOver), content.top, tx-2, content.bottom), FBarColor);
-               ABitmap.SetPixel(tx-2-(rMarqueeWidth+1-marqueeOver), content.top, BGRA(62, 62, 62));
-               ABitmap.SetVertLine(tx-2-(rMarqueeWidth+1-marqueeOver), content.top + 1, content.bottom - 1, BGRA(40, 40, 40));
+               DrawBar(rect(content.Right-(rMarqueeWidth+1-marqueeOver), content.top, tx-2, content.bottom), FBarColor);
+               ABitmap.SetPixel(content.Right-(rMarqueeWidth+1-marqueeOver), content.top, BGRA(62, 62, 62));
+               ABitmap.SetVertLine(content.Right-(rMarqueeWidth+1-marqueeOver), content.top + 1, content.bottom - 1, BGRA(40, 40, 40));
              end;
-
       end;
       pbstTimer: begin
         if FMaxValue > FMinValue then
@@ -873,6 +935,18 @@ begin
   end;
 end;
 
+procedure TBGRAFlashProgressBar.StepIt(AIncrement: Double);
+begin
+  Case FStyle of
+    pbstMarquee,
+    pbstTimer: begin
+      internalTimer.Enabled:= False;
+      TimerOnTimer(nil);
+    end
+  else Value:= Value+AIncrement;
+  end;
+end;
+
 procedure TBGRAFlashProgressBar.TimerReStart;
 begin
   if (FStyle = pbstTimer) then
@@ -888,7 +962,7 @@ end;
 
 procedure TBGRAFlashProgressBar.TimerPlayPause;
 begin
-  if (FStyle = pbstTimer) then
+  if (FStyle in [pbstMarquee, pbstTimer]) then
   begin
     internalTimer.Enabled:= not(internalTimer.Enabled);
     Invalidate;

+ 97 - 52
test/test_progressbar/umain.lfm

@@ -1,15 +1,15 @@
 object Form1: TForm1
   Left = 357
-  Height = 374
+  Height = 418
   Top = 179
-  Width = 541
+  Width = 506
   Caption = 'Form1'
-  ClientHeight = 374
-  ClientWidth = 541
+  ClientHeight = 418
+  ClientWidth = 506
   object btStyleMarquee: TBGRASpeedButton
-    Left = 99
+    Left = 112
     Height = 22
-    Top = 160
+    Top = 152
     Width = 64
     Caption = 'Marquee'
     OnClick = btStyleMarqueeClick
@@ -37,10 +37,10 @@ object Form1: TForm1
     OnTimerEnd = BGRAMaxMProgressTimerEnd
   end
   object rgMarqueeSpeed: TRadioGroup
-    Left = 115
+    Left = 112
     Height = 65
-    Top = 228
-    Width = 79
+    Top = 246
+    Width = 77
     AutoFill = True
     Caption = 'Speed'
     ChildSizing.LeftRightSpacing = 6
@@ -51,7 +51,7 @@ object Form1: TForm1
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.ControlsPerLine = 1
     ClientHeight = 45
-    ClientWidth = 75
+    ClientWidth = 73
     ItemIndex = 1
     Items.Strings = (
       'Slow'
@@ -62,9 +62,9 @@ object Form1: TForm1
     OnClick = rgMarqueeSpeedClick
   end
   object edMarqueeWidth: TBCTrackbarUpdown
-    Left = 130
+    Left = 131
     Height = 26
-    Top = 343
+    Top = 389
     Width = 64
     AllowNegativeValues = False
     BarExponent = 1
@@ -139,16 +139,16 @@ object Form1: TForm1
     UseDockManager = False
   end
   object Label1: TLabel
-    Left = 115
+    Left = 116
     Height = 15
-    Top = 304
+    Top = 350
     Width = 38
     Caption = 'Width :'
   end
   object btStyleMultiP: TBGRASpeedButton
-    Left = 239
+    Left = 248
     Height = 22
-    Top = 160
+    Top = 152
     Width = 79
     Caption = 'MultiProgress'
     OnClick = btStyleMultiPClick
@@ -161,16 +161,16 @@ object Form1: TForm1
     Caption = 'Value :'
   end
   object Label3: TLabel
-    Left = 255
+    Left = 248
     Height = 15
-    Top = 191
+    Top = 183
     Width = 48
     Caption = 'Value M :'
   end
   object cbMarqueeWidth: TCheckBox
-    Left = 130
+    Left = 131
     Height = 19
-    Top = 320
+    Top = 366
     Width = 44
     Caption = 'Auto'
     Checked = True
@@ -181,7 +181,7 @@ object Form1: TForm1
   object edCaption: TEdit
     Left = 60
     Height = 23
-    Top = 80
+    Top = 72
     Width = 80
     TabOrder = 3
     OnChange = edCaptionChange
@@ -189,30 +189,30 @@ object Form1: TForm1
   object Label4: TLabel
     Left = 8
     Height = 15
-    Top = 84
+    Top = 76
     Width = 48
     Caption = 'Caption :'
   end
   object cbCaptionPercent: TCheckBox
-    Left = 4
+    Left = 233
     Height = 19
-    Top = 186
-    Width = 90
-    Caption = 'Show Percent'
+    Top = 76
+    Width = 119
+    Caption = 'Show Total Percent'
     TabOrder = 4
     OnChange = cbCaptionPercentChange
   end
   object Label6: TLabel
-    Left = 8
+    Left = 233
     Height = 15
-    Top = 206
+    Top = 98
     Width = 36
     Caption = 'Digits :'
   end
   object edCaptionDigits: TSpinEdit
-    Left = 48
+    Left = 277
     Height = 23
-    Top = 206
+    Top = 96
     Width = 50
     MaxValue = 30
     TabOrder = 5
@@ -232,9 +232,9 @@ object Form1: TForm1
     OnChange = edValueChange
   end
   object edMultiPValueM: TFloatSpinEdit
-    Left = 304
+    Left = 297
     Height = 23
-    Top = 186
+    Top = 178
     Width = 80
     Font.Color = clWindowText
     Font.Name = 'Arial'
@@ -286,7 +286,7 @@ object Form1: TForm1
   object rgCaptionAlign: TRadioGroup
     Left = 147
     Height = 65
-    Top = 80
+    Top = 72
     Width = 79
     AutoFill = True
     Caption = 'Align'
@@ -309,18 +309,18 @@ object Form1: TForm1
     OnClick = rgCaptionAlignClick
   end
   object cbCaptionPercentM: TCheckBox
-    Left = 255
+    Left = 248
     Height = 19
-    Top = 216
-    Width = 90
-    Caption = 'Show Percent'
+    Top = 208
+    Width = 133
+    Caption = 'Show ValueM Percent'
     TabOrder = 11
     OnChange = cbCaptionPercentMChange
   end
   object rgCaptionAlignM: TRadioGroup
-    Left = 271
+    Left = 264
     Height = 65
-    Top = 238
+    Top = 230
     Width = 79
     AutoFill = True
     Caption = 'Align'
@@ -343,9 +343,9 @@ object Form1: TForm1
     OnClick = rgCaptionAlignMClick
   end
   object rgMarqueeDirection: TRadioGroup
-    Left = 119
+    Left = 116
     Height = 41
-    Top = 181
+    Top = 312
     Width = 107
     AutoFill = True
     Caption = 'Direction'
@@ -370,7 +370,7 @@ object Form1: TForm1
   object btStyleNormal: TBGRASpeedButton
     Left = 4
     Height = 22
-    Top = 160
+    Top = 152
     Width = 79
     Caption = 'Normal'
     OnClick = btStyleNormalClick
@@ -378,7 +378,7 @@ object Form1: TForm1
   object btStyleTimer: TBGRASpeedButton
     Left = 392
     Height = 22
-    Top = 160
+    Top = 152
     Width = 79
     Caption = 'Timer'
     OnClick = btStyleTimerClick
@@ -386,15 +386,15 @@ object Form1: TForm1
   object btTimerStart: TBGRASpeedButton
     Left = 408
     Height = 22
-    Top = 238
+    Top = 230
     Width = 63
     Caption = 'ReStart'
     OnClick = btTimerStartClick
   end
   object cbTimerAutoStart: TCheckBox
-    Left = 400
+    Left = 392
     Height = 19
-    Top = 216
+    Top = 176
     Width = 71
     Caption = 'Auto Start'
     Checked = True
@@ -405,15 +405,15 @@ object Form1: TForm1
   object btTimerPlayPause: TBGRASpeedButton
     Left = 408
     Height = 22
-    Top = 262
+    Top = 254
     Width = 63
     Caption = 'Play/Pause'
     OnClick = btTimerPlayPauseClick
   end
   object TimeEdit1: TTimeEdit
-    Left = 400
+    Left = 392
     Height = 23
-    Top = 186
+    Top = 196
     Width = 103
     ButtonWidth = 23
     NumGlyphs = 1
@@ -424,7 +424,7 @@ object Form1: TForm1
   object cbCaptionPercent1: TCheckBox
     Left = 400
     Height = 19
-    Top = 296
+    Top = 288
     Width = 80
     Caption = 'Show Timer'
     TabOrder = 16
@@ -433,7 +433,7 @@ object Form1: TForm1
   object edCaptionTimerFormat: TEdit
     Left = 408
     Height = 23
-    Top = 318
+    Top = 310
     Width = 80
     TabOrder = 17
     Text = 'nn:ss.zzz'
@@ -442,11 +442,56 @@ object Form1: TForm1
   object lbCount: TLabel
     Left = 400
     Height = 25
-    Top = 344
+    Top = 336
     Width = 8
     Caption = '_'
     Font.Color = clRed
     Font.Height = -19
     ParentFont = False
   end
+  object btTimerPlayPause1: TBGRASpeedButton
+    Left = 116
+    Height = 22
+    Top = 197
+    Width = 63
+    Caption = 'Play/Pause'
+    OnClick = btTimerPlayPauseClick
+  end
+  object btTimerPlayPause2: TBGRASpeedButton
+    Left = 180
+    Height = 22
+    Top = 197
+    Width = 40
+    Caption = 'StepIt'
+    OnClick = btTimerPlayPause2Click
+  end
+  object cbTimerAutoStart1: TCheckBox
+    Left = 116
+    Height = 19
+    Top = 176
+    Width = 71
+    Caption = 'Auto Start'
+    Checked = True
+    State = cbChecked
+    TabOrder = 18
+    OnChange = cbTimerAutoStartChange
+  end
+  object edMarqueeBounce: TSpinEdit
+    Left = 170
+    Height = 23
+    Hint = '0 = Normal Marquee;'#13#10'>0 Bounce'
+    Top = 224
+    Width = 50
+    MaxValue = 10
+    ParentShowHint = False
+    TabOrder = 19
+    OnChange = edMarqueeBounceChange
+  end
+  object Label8: TLabel
+    Left = 119
+    Height = 15
+    Top = 226
+    Width = 43
+    Caption = 'Bounce:'
+  end
 end

+ 18 - 1
test/test_progressbar/umain.pas

@@ -16,6 +16,8 @@ type
     btStyleMultiP: TBGRASpeedButton;
     btStyleNormal: TBGRASpeedButton;
     btStyleTimer: TBGRASpeedButton;
+    btTimerPlayPause1: TBGRASpeedButton;
+    btTimerPlayPause2: TBGRASpeedButton;
     btTimerStart: TBGRASpeedButton;
     btTimerPlayPause: TBGRASpeedButton;
     cbCaptionPercent1: TCheckBox;
@@ -23,6 +25,7 @@ type
     cbMarqueeWidth: TCheckBox;
     cbCaptionPercent: TCheckBox;
     cbTimerAutoStart: TCheckBox;
+    cbTimerAutoStart1: TCheckBox;
     edCaption: TEdit;
     edCaptionTimerFormat: TEdit;
     edMarqueeWidth: TBCTrackbarUpdown;
@@ -39,12 +42,14 @@ type
     Label5: TLabel;
     Label6: TLabel;
     Label7: TLabel;
+    Label8: TLabel;
     lbCount: TLabel;
     rgCaptionAlignM: TRadioGroup;
     rgMarqueeSpeed: TRadioGroup;
     edCaptionDigits: TSpinEdit;
     rgCaptionAlign: TRadioGroup;
     rgMarqueeDirection: TRadioGroup;
+    edMarqueeBounce: TSpinEdit;
     TimeEdit1: TTimeEdit;
     procedure BCTrackbarUpdown1Change(Sender: TObject; AByUser: boolean);
     procedure BGRAMaxMProgressTimerEnd(Sender: TObject);
@@ -52,6 +57,7 @@ type
     procedure btStyleMultiPClick(Sender: TObject);
     procedure btStyleNormalClick(Sender: TObject);
     procedure btStyleTimerClick(Sender: TObject);
+    procedure btTimerPlayPause2Click(Sender: TObject);
     procedure btTimerPlayPauseClick(Sender: TObject);
     procedure btTimerStartClick(Sender: TObject);
     procedure cbCaptionPercentMChange(Sender: TObject);
@@ -60,6 +66,7 @@ type
     procedure cbTimerAutoStartChange(Sender: TObject);
     procedure edCaptionChange(Sender: TObject);
     procedure edCaptionDigitsChange(Sender: TObject);
+    procedure edMarqueeBounceChange(Sender: TObject);
     procedure edMaxChange(Sender: TObject);
     procedure edMinChange(Sender: TObject);
     procedure edMultiPValueMChange(Sender: TObject; AByUser: boolean);
@@ -113,6 +120,11 @@ begin
   BGRAMaxMProgress.Style:= pbstTimer;
 end;
 
+procedure TForm1.btTimerPlayPause2Click(Sender: TObject);
+begin
+  BGRAMaxMProgress.StepIt(0);
+end;
+
 procedure TForm1.btTimerPlayPauseClick(Sender: TObject);
 begin
   BGRAMaxMProgress.TimerPlayPause;
@@ -148,7 +160,7 @@ end;
 
 procedure TForm1.cbTimerAutoStartChange(Sender: TObject);
 begin
-  BGRAMaxMProgress.TimerAutoRestart:= cbTimerAutoStart.Checked;
+  BGRAMaxMProgress.TimerAutoRestart:= TCheckBox(Sender).Checked;
 end;
 
 procedure TForm1.edCaptionChange(Sender: TObject);
@@ -161,6 +173,11 @@ begin
   BGRAMaxMProgress.CaptionPercentDigits:= edCaptionDigits.Value;
 end;
 
+procedure TForm1.edMarqueeBounceChange(Sender: TObject);
+begin
+  BGRAMaxMProgress.MarqueeBounce:= edMarqueeBounce.Value;
+end;
+
 procedure TForm1.edMaxChange(Sender: TObject);
 begin
   BGRAMaxMProgress.MaxValue:=edMax.Value;