summaryrefslogtreecommitdiff
path: root/gui/scrollbar.inc
diff options
context:
space:
mode:
Diffstat (limited to 'gui/scrollbar.inc')
-rw-r--r--gui/scrollbar.inc730
1 files changed, 730 insertions, 0 deletions
diff --git a/gui/scrollbar.inc b/gui/scrollbar.inc
new file mode 100644
index 00000000..8a24584b
--- /dev/null
+++ b/gui/scrollbar.inc
@@ -0,0 +1,730 @@
+{
+ fpGUI - Free Pascal Graphical User Interface
+ Copyright (C) 2000 - 2001 by
+ Areca Systems GmbH / Sebastian Guenther
+ Copyright (C) 2006 by Graeme Geldenhuys
+ member of the fpGUI development team.
+
+ Scrollbar class declarations
+
+ See the file COPYING.fpGUI, included in this distribution,
+ for details about the copyright.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+
+{%mainunit fpgui.pp}
+
+{$IFDEF read_interface}
+
+ // !!!: Add argument which indicates the type of scrolling
+ TScrollEvent = procedure(Sender: TObject; var APosition: Integer) of object;
+
+
+ TCustomScrollBar = class(TWidget)
+ private
+ FOrientation: TOrientation;
+ FMin: Integer;
+ FMax: Integer;
+ FPageSize: Integer;
+ FPosition: Integer;
+ FSmallChange: Integer;
+ FLargeChange: Integer;
+ FOnChange: TNotifyEvent;
+ FOnScroll: TScrollEvent;
+ ButtonUp: TGenericButton;
+ ButtonDown: TGenericButton;
+ Slider: TWidget;
+ Embedded: Boolean; // for internal embedded usage!
+
+ // Event handling
+ procedure ButtonUpClick(Sender: TObject);
+ procedure ButtonDownClick(Sender: TObject);
+ // Property access
+ procedure SetOrientation(AOrientation: TOrientation);
+ procedure SetMin(AMin: Integer);
+ procedure SetMax(AMax: Integer);
+ procedure SetPageSize(APageSize: Integer);
+ procedure SetPosition(APosition: Integer);
+ // Helpers
+ function GetButtonSize: Integer;
+ function ClipPosition(APosition: Integer): Integer;
+ procedure UpdateBar;
+ protected
+ function DistributeEvent(Event: TEventObj): Boolean; override;
+ procedure Paint(Canvas: TFCanvas); override;
+ procedure CalcSizes; override;
+ procedure Resized; override;
+ property Orientation: TOrientation read FOrientation write SetOrientation;
+ property Min: Integer read FMin write SetMin default 0;
+ property Max: Integer read FMax write SetMax default 100;
+ property PageSize: Integer read FPageSize write SetPageSize;
+ property Position: Integer read FPosition write SetPosition default 0;
+ property SmallChange: Integer read FSmallChange write FSmallChange default 1;
+ property LargeChange: Integer read FLargeChange write FLargeChange default 0;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ property OnScroll: TScrollEvent read FOnScroll write FOnScroll;
+ public
+ constructor Create(AOwner: TComponent); override;
+ procedure LineUp;
+ procedure LineDown;
+ procedure PageUp;
+ procedure PageDown;
+ end;
+
+
+ TScrollBar = class(TCustomScrollBar)
+ published
+ property Enabled;
+ property Orientation;
+ property Min;
+ property Max;
+ property PageSize;
+ property Position;
+ property SmallChange;
+ property LargeChange;
+ property OnChange;
+ property OnScroll;
+ end;
+
+
+{$ENDIF read_interface}
+
+
+
+{$IFDEF read_implementation}
+
+
+
+// ===================================================================
+// TCustomScrollBar and helper classes
+// ===================================================================
+
+// -------------------------------------------------------------------
+// TScrollBarButton
+// -------------------------------------------------------------------
+
+type
+ { Private button type only used for scrollbars. }
+ TScrollBarButton = class(TGenericButton)
+ protected
+ procedure Paint(Canvas: TFCanvas); override;
+ procedure CalcSizes; override;
+ public
+ Direction: TArrowDirection;
+ end;
+
+
+procedure TScrollBarButton.Paint(Canvas: TFCanvas);
+begin
+ inherited Paint(Canvas);
+ Style.DrawScrollBarButton(Canvas, Rect(0, 0, BoundsSize.cx, BoundsSize.cy),
+ Direction, (wsClicked in WidgetState) and (wsMouseInside in WidgetState),
+ wsEnabled in WidgetState);
+end;
+
+
+procedure TScrollBarButton.CalcSizes;
+begin
+ ASSERT(Owner is TCustomScrollBar);
+ FMinSize := Style.GetScrollBarBtnSize(TCustomScrollBar(Owner).Orientation);
+end;
+
+
+// -------------------------------------------------------------------
+// TScrollBarSlider
+// -------------------------------------------------------------------
+
+type
+ TScrollBarSlider = class(TWidget)
+ private
+ function EvMousePressed(Event: TMousePressedEventObj): Boolean;
+ function EvMouseReleased(Event: TMouseReleasedEventObj): Boolean;
+ function EvMouseMove(Event: TMouseMoveEventObj): Boolean;
+ protected
+ ButtonPos: Integer;
+ ButtonSize: Integer;
+ IsDraggingButton: Boolean;
+ PrevAreaPressed: Boolean;
+ NextAreaPressed: Boolean;
+ DragStartMousePos: Integer;
+ DragStartButtonPos: Integer;
+// ButtonMoveSavedPosition: Integer;
+ procedure Paint(Canvas: TFCanvas); override;
+ function ProcessEvent(Event: TEventObj): Boolean; override;
+ procedure CalcSizes; override;
+ function CalcPosition: Integer;
+ public
+ constructor Create(AOwner: TComponent); override;
+ procedure UpdateBar;
+ end;
+
+
+constructor TScrollBarSlider.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ WidgetStyle := WidgetStyle + [wsCaptureMouse, wsClickable, wsOpaque];
+end;
+
+
+procedure TScrollBarSlider.UpdateBar;
+var
+ Size: Integer;
+begin
+ ASSERT(Owner is TCustomScrollBar);
+
+ if Visible then
+ begin
+ with TCustomScrollBar(Owner) do
+ begin
+ if (Min = Max) or (Max - Min = PageSize - 1) then
+ ButtonPos := 0
+ else
+ begin
+ if Orientation = Horizontal then
+ Size := Self.BoundsSize.cx
+ else
+ Size := Self.BoundsSize.cy;
+
+ if PageSize = 0 then
+ ButtonPos := (Position - Min) * (Size - ButtonSize) div (Max - Min)
+ else
+ ButtonPos := (Position - Min) *
+ (Size - ButtonSize) div (Max - Min - PageSize + 1);
+ end;
+ ButtonSize := GetButtonSize;
+ end;
+ Redraw;
+ end;
+end;
+
+
+procedure TScrollBarSlider.Paint(Canvas: TFCanvas);
+var
+ Size: Integer;
+ r: TRect;
+ StartPos, EndPos: PInteger;
+ Color2: TColor;
+begin
+ ASSERT(Owner is TCustomScrollBar);
+ inherited Paint(Canvas);
+
+ if TCustomScrollBar(Owner).Orientation = Horizontal then
+ begin
+ r.Top := 0;
+ r.Bottom := Height;
+ StartPos := @r.Left;
+ EndPos := @r.Right;
+ Size := Width;
+ end else
+ begin
+ r.Left := 0;
+ r.Right := Width;
+ StartPos := @r.Top;
+ EndPos := @r.Bottom;
+ Size := Height;
+ end;
+
+ if ButtonPos > 0 then
+ begin
+ if PrevAreaPressed then
+ Color2 := cl3DDkShadow
+ else
+ Color2 := cl3DLight;
+ Canvas.SetColor(GetAvgColor(Style.GetUIColor(clScrollBar),
+ Style.GetUIColor(Color2)));
+ StartPos^ := 0;
+ EndPos^ := ButtonPos;
+ Canvas.FillRect(r);
+ end;
+ if ButtonPos + ButtonSize < Size then
+ begin
+ if NextAreaPressed then
+ Color2 := cl3DDkShadow
+ else
+ Color2 := cl3DLight;
+ Canvas.SetColor(GetAvgColor(Style.GetUIColor(clScrollBar),
+ Style.GetUIColor(Color2)));
+ StartPos^ := ButtonPos + ButtonSize;
+ EndPos^ := Size;
+ Canvas.FillRect(r);
+ end;
+
+ StartPos^ := ButtonPos;
+ EndPos^ := ButtonPos + ButtonSize;
+ Style.DrawButtonFace(Canvas, r, [btnIsEmbedded]);
+end;
+
+
+function TScrollBarSlider.ProcessEvent(Event: TEventObj): Boolean;
+begin
+ Result := False;
+ if Event.InheritsFrom(TMousePressedEventObj) then
+ Result := EvMousePressed(TMousePressedEventObj(Event))
+ else if Event.InheritsFrom(TMouseReleasedEventObj) then
+ Result := EvMouseReleased(TMouseReleasedEventObj(Event))
+ else if Event.InheritsFrom(TMouseMoveEventObj) then
+ Result := EvMouseMove(TMouseMoveEventObj(Event));
+
+ if not Result then
+ Result := inherited ProcessEvent(Event);
+
+ if Event.InheritsFrom(TVisibilityChangeEventObj) and Visible then
+ UpdateBar;
+end;
+
+
+function TScrollBarSlider.EvMousePressed(Event: TMousePressedEventObj): Boolean;
+var
+ Pos: Integer;
+begin
+ Result := inherited ProcessEvent(Event); // For mouse grabbing support
+
+ if Event.Button <> mbLeft then
+ exit;
+
+ if TCustomScrollBar(Owner).Orientation = Horizontal then
+ Pos := Event.Position.x
+ else
+ Pos := Event.Position.y;
+
+ if Pos < ButtonPos then
+ begin
+ PrevAreaPressed := True;
+ TCustomScrollBar(Owner).PageUp
+ end
+ else if Pos > ButtonPos + ButtonSize then
+ begin
+ NextAreaPressed := True;
+ TCustomScrollBar(Owner).PageDown
+ end
+ else
+ begin
+ IsDraggingButton := True;
+ DragStartMousePos := Pos;
+ DragStartButtonPos := ButtonPos;
+ end;
+
+ Result := True;
+end;
+
+
+function TScrollBarSlider.EvMouseReleased(
+ Event: TMouseReleasedEventObj): Boolean;
+var
+ NewPosition: Integer;
+begin
+ Result := inherited ProcessEvent(Event); // For mouse grabbing support
+
+ if Event.Button <> mbLeft then
+ exit;
+
+ if IsDraggingButton then
+ begin
+ IsDraggingButton := False;
+ NewPosition := CalcPosition;
+ if NewPosition <> TCustomScrollBar(Owner).Position then
+ begin
+ if Assigned(TCustomScrollBar(Owner).OnScroll) then
+ TCustomScrollBar(Owner).OnScroll(Owner, NewPosition);
+ TCustomScrollBar(Owner).FPosition := NewPosition;
+ end;
+ if (NewPosition <> DragStartMousePos) and
+ Assigned(TCustomScrollBar(Owner).OnChange) then
+ TCustomScrollBar(Owner).OnChange(Self);
+ UpdateBar;
+ end
+ else if PrevAreaPressed then
+ begin
+ PrevAreaPressed := False;
+ Redraw;
+ end
+ else if NextAreaPressed then
+ begin
+ NextAreaPressed := False;
+ Redraw;
+ end;
+ Result := True;
+end;
+
+
+function TScrollBarSlider.EvMouseMove(Event: TMouseMoveEventObj): Boolean;
+var
+ Pos, Size, VirtualPos: Integer;
+begin
+ if IsDraggingButton then
+ begin
+ if wsMouseInside in WidgetState then
+ if TCustomScrollBar(Owner).Orientation = Horizontal then
+ begin
+ Pos := Event.Position.x;
+ Size := Width;
+ end else
+ begin
+ Pos := Event.Position.y;
+ Size := Height;
+ end
+ else
+ begin
+ Pos := DragStartMousePos;
+ if TCustomScrollBar(Owner).Orientation = Horizontal then
+ Size := Width
+ else
+ Size := Height;
+ end;
+
+ ButtonPos := ClipMinMax(DragStartButtonPos + Pos - DragStartMousePos,
+ 0, Size - ButtonSize);
+ VirtualPos := CalcPosition;
+
+ if VirtualPos <> TCustomScrollBar(Owner).Position then
+ begin
+ if Assigned(TCustomScrollBar(Owner).OnScroll) then
+ TCustomScrollBar(Owner).OnScroll(Owner, VirtualPos);
+ TCustomScrollBar(Owner).FPosition := VirtualPos;
+ end;
+
+ Redraw;
+ Result := True
+ end else
+ Result := False;
+end;
+
+
+procedure TScrollBarSlider.CalcSizes;
+begin
+ if TCustomScrollBar(Owner).Orientation = Horizontal then
+ FDefSize.cx := Style.GetScrollBarBtnSize(Horizontal).cy * 5
+ else
+ FDefSize.cy := Style.GetScrollBarBtnSize(Vertical).cx * 5;
+end;
+
+
+function TScrollBarSlider.CalcPosition: Integer;
+var
+ Size: Integer;
+begin
+ with TCustomScrollBar(Owner) do
+ begin
+ if Orientation = Horizontal then
+ Size := Self.Width
+ else
+ Size := Self.Height;
+
+ if Size = ButtonSize then
+ Position := 0
+ else
+ begin
+ if PageSize = 0 then
+ Result := ButtonPos * (Max - Min + 1)
+ else
+ Result := ButtonPos * (Max - Min - PageSize + 2);
+ Result := Result div (Size - ButtonSize);
+ Result := Result + Min;
+ end;
+ Result := ClipPosition(Result);
+ end;
+end;
+
+
+// -------------------------------------------------------------------
+// TCustomScrollBar
+// -------------------------------------------------------------------
+
+constructor TCustomScrollBar.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ Include(WidgetStyle, wsOpaque);
+ Embedded := False;
+
+ FMax := 100;
+ FSmallChange := 1;
+
+ ButtonUp := TScrollBarButton.Create(Self);
+ ButtonUp.Name := '#ScrollBarButtonUp';
+ TScrollBarButton(ButtonUp).Direction := arrowLeft;
+ ButtonUp.Embedded := True;
+ ButtonUp.CanExpandWidth := False;
+ ButtonUp.CanExpandHeight := False;
+ ButtonUp.OnClick := @ButtonUpClick;
+ ButtonUp.SetEmbeddedParent(Self);
+
+ Slider := TScrollBarSlider.Create(Self);
+ Slider.Name := '#ScrollBarSlider';
+ Slider.SetEmbeddedParent(Self);
+
+ ButtonDown := TScrollBarButton.Create(Self);
+ ButtonDown.Name := '#ScrollBarButtonDown';
+ TScrollBarButton(ButtonDown).Direction := arrowRight;
+ ButtonDown.Embedded := True;
+ ButtonDown.CanExpandWidth := False;
+ ButtonDown.CanExpandHeight := False;
+ ButtonDown.OnClick := @ButtonDownClick;
+ ButtonDown.SetEmbeddedParent(Self);
+end;
+
+
+procedure TCustomScrollBar.LineUp;
+begin
+ Position := Position - SmallChange;
+end;
+
+
+procedure TCustomScrollBar.LineDown;
+begin
+ Position := Position + SmallChange;
+end;
+
+
+procedure TCustomScrollBar.PageUp;
+var
+ Diff: Integer;
+begin
+ if LargeChange = 0 then
+ begin
+ Diff := (Max - Min + 6) div 10;
+ if Diff = 0 then
+ Inc(Diff);
+ Position := Position - Diff;
+ end else
+ Position := Position - LargeChange;
+end;
+
+
+procedure TCustomScrollBar.PageDown;
+var
+ Diff: Integer;
+begin
+ if LargeChange = 0 then
+ begin
+ Diff := (Max - Min + 6) div 10;
+ if Diff = 0 then
+ Inc(Diff);
+ Position := Position + Diff;
+ end else
+ Position := Position + LargeChange;
+end;
+
+
+function TCustomScrollBar.DistributeEvent(Event: TEventObj): Boolean;
+begin
+ Result := Event.SendToChild(Slider) or Event.SendToChild(ButtonUp) or
+ Event.SendToChild(ButtonDown);
+end;
+
+
+procedure TCustomScrollBar.Paint(Canvas: TFCanvas);
+begin
+ if not Embedded then
+ Style.DrawScrollBarBorder(Canvas, Rect(0, 0, Width, Height));
+end;
+
+
+procedure TCustomScrollBar.CalcSizes;
+begin
+ if Orientation = Horizontal then
+ begin
+ FMinSize.cx := ButtonUp.DefSize.cx + Slider.MinSize.cx + ButtonDown.DefSize.cx;
+ FMinSize.cy := ButtonUp.DefSize.cy;
+ FDefSize.cx := ButtonUp.DefSize.cx + Slider.DefSize.cx + ButtonDown.DefSize.cx;
+ FDefSize.cy := ButtonUp.DefSize.cy;
+ FMaxSize.cx := InfiniteSize;
+ FMaxSize.cy := ButtonUp.DefSize.cy;
+ end else
+ begin
+ FMinSize.cx := ButtonUp.DefSize.cx;
+ FMinSize.cy := ButtonUp.DefSize.cy + Slider.MinSize.cy + ButtonDown.DefSize.cy;
+ FDefSize.cx := ButtonUp.DefSize.cx;
+ FDefSize.cy := ButtonUp.DefSize.cy + Slider.DefSize.cy + ButtonDown.DefSize.cy;
+ FMaxSize.cx := ButtonUp.DefSize.cx;
+ FMaxSize.cy := InfiniteSize;
+ end;
+
+ if not Embedded then
+ with Style.GetScrollBarBorders(Orientation) do
+ begin
+ Inc(FMinSize.cx, Left + Right);
+ Inc(FMinSize.cy, Top + Bottom);
+ FDefSize.cx := fpGUI.Min(DefSize.cx + Left + Right, InfiniteSize);
+ FDefSize.cy := fpGUI.Min(DefSize.cy + Top + Bottom, InfiniteSize);
+ FMaxSize.cx := fpGUI.Min(MaxSize.cx + Left + Right, InfiniteSize);
+ FMaxSize.cy := fpGUI.Min(MaxSize.cy + Top + Bottom, InfiniteSize);
+ end;
+end;
+
+
+procedure TCustomScrollBar.Resized;
+var
+ r: TRect;
+begin
+ if not Embedded then
+ with Style.GetScrollBarBorders(Orientation) do
+ begin
+ r.Left := Left;
+ r.Top := Top;
+ r.Right := Width - Right;
+ r.Bottom := Height - Bottom;
+ end
+ else
+ begin
+ r.Left := 0;
+ r.Top := 0;
+ r.Right := Width;
+ r.Bottom := Height;
+ end;
+
+ with r do
+ if Orientation = Horizontal then
+ begin
+ ButtonUp.SetBounds(TopLeft, Size(ButtonUp.DefSize.cx, Bottom - Top));
+ ButtonDown.SetBounds(Point(Right - ButtonDown.DefSize.cx, Top),
+ Size(ButtonDown.DefSize.cx, Bottom - Top));
+ Slider.SetBounds(Point(Left + ButtonUp.DefSize.cx, Top),
+ Size(Right - Left - ButtonUp.DefSize.cx - ButtonDown.DefSize.cx,
+ Bottom - Top));
+ end
+ else
+ begin
+ ButtonUp.SetBounds(TopLeft, Size(Right - Left, ButtonDown.DefSize.cy));
+ ButtonDown.SetBounds(Point(Left, Bottom - ButtonDown.DefSize.cy),
+ Size(Right - Left, ButtonDown.DefSize.cy));
+ Slider.SetBounds(Point(Left, Top + ButtonUp.DefSize.cy),
+ Size(Right - Left,
+ Bottom - Top - ButtonUp.DefSize.cy - ButtonDown.DefSize.cy));
+ end;
+
+ UpdateBar;
+end;
+
+
+procedure TCustomScrollBar.ButtonUpClick(Sender: TObject);
+begin
+ LineUp;
+end;
+
+
+procedure TCustomScrollBar.ButtonDownClick(Sender: TObject);
+begin
+ LineDown;
+end;
+
+
+procedure TCustomScrollBar.SetOrientation(AOrientation: TOrientation);
+begin
+ if AOrientation <> Orientation then
+ begin
+ FOrientation := AOrientation;
+ if Orientation = Horizontal then
+ begin
+ TScrollBarButton(ButtonUp).Direction := arrowLeft;
+ TScrollBarButton(ButtonDown).Direction := arrowRight;
+ end else
+ begin
+ TScrollBarButton(ButtonUp).Direction := arrowUp;
+ TScrollBarButton(ButtonDown).Direction := arrowDown;
+ end;
+ end;
+end;
+
+
+procedure TCustomScrollBar.SetMin(AMin: Integer);
+begin
+ if AMin <> FMin then
+ begin
+ FMin := AMin;
+ Position := Position; // Do range clipping
+ UpdateBar;
+ end;
+end;
+
+
+procedure TCustomScrollBar.SetMax(AMax: Integer);
+begin
+ if AMax <> FMax then
+ begin
+ FMax := AMax;
+ Position := Position; // Do range clipping
+ UpdateBar;
+ end;
+end;
+
+
+procedure TCustomScrollBar.SetPageSize(APageSize: Integer);
+begin
+ if FPageSize <> APageSize then
+ begin
+ FPageSize := APageSize;
+ Position := Position; // Do range clipping
+ UpdateBar;
+ end;
+end;
+
+
+procedure TCustomScrollBar.SetPosition(APosition: Integer);
+begin
+ APosition := ClipPosition(APosition);
+
+ if (APosition <> Position) and Assigned(OnScroll) then
+ OnScroll(Self, APosition);
+
+ if APosition <> Position then
+ begin
+ FPosition := APosition;
+ UpdateBar;
+ if Assigned(OnChange) then
+ OnChange(Self);
+ end;
+end;
+
+
+function TCustomScrollBar.GetButtonSize: Integer;
+var
+ Size: Integer;
+begin
+ if PageSize = 0 then
+ if Orientation = Horizontal then
+ Result := Height
+ else
+ Result := Width
+ else
+ begin
+ if Orientation = Horizontal then
+ Size := Slider.Width
+ else
+ Size := Slider.Height;
+ Result := fpGUI.Max(Style.GetScrollBarBtnMinSize,
+ PageSize * Size div fpGUI.Max(1, Max - Min + 1));
+ if Result > Size then
+ Result := Size;
+ end;
+end;
+
+
+function TCustomScrollBar.ClipPosition(APosition: Integer): Integer;
+begin
+ if APosition > Max - PageSize then
+ if PageSize = 0 then
+ Result := Max
+ else
+ Result := Max - PageSize + 1
+ else
+ Result := APosition;
+ if Result < Min then
+ Result := Min;
+end;
+
+
+procedure TCustomScrollBar.UpdateBar;
+begin
+ if Embedded then
+ Visible := (Max > Min) and ((PageSize = 0) or (PageSize <= Max - Min));
+ TScrollBarSlider(Slider).UpdateBar;
+end;
+
+
+{$ENDIF read_implementation}
+