{*********************************************************} {* OVCSC.PAS 4.06 *} {*********************************************************} {* ***** BEGIN LICENSE BLOCK ***** *} {* Version: MPL 1.1 *} {* *} {* The contents of this file are subject to the Mozilla Public License *} {* Version 1.1 (the "License"); you may not use this file except in *} {* compliance with the License. You may obtain a copy of the License at *} {* http://www.mozilla.org/MPL/ *} {* *} {* Software distributed under the License is distributed on an "AS IS" basis, *} {* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *} {* for the specific language governing rights and limitations under the *} {* License. *} {* *} {* The Original Code is TurboPower Orpheus *} {* *} {* The Initial Developer of the Original Code is TurboPower Software *} {* *} {* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *} {* TurboPower Software Inc. All Rights Reserved. *} {* *} {* Contributor(s): *} {* *} {* ***** END LICENSE BLOCK ***** *} (*Changes) 01/15/02 - Set AutoRepeat modified to prevent deadlocks at runtime. *) {$I OVC.INC} {$B-} {Complete Boolean Evaluation} {$I+} {Input/Output-Checking} {$P+} {Open Parameters} {$T-} {Typed @ Operator} {.W-} {Windows Stack Frame} {$X+} {Extended Syntax} unit ovcsc; {-Spin control} interface uses {$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF} Buttons, Classes, Controls, Forms, Graphics, StdCtrls, SysUtils, OvcBase, OvcData, OvcEF, OvcMisc, OvcExcpt; type TOvcSpinnerStyle = (stNormalVertical, stNormalHorizontal, stFourWay, stStar, stDiagonalVertical, stDiagonalHorizontal, stDiagonalFourWay, stPlainStar); TOvcDirection = (dUp, dDown, dRight, dLeft); TOvcSpinState = (ssNone, ssNormal, ssUpBtn, ssDownBtn, ssLeftBtn, ssRightBtn, ssCenterBtn); TOvcSpinnerLineType = (ltSingle, ltTopBevel, ltBottomBevel, ltTopSlice, ltBottomSlice, ltTopSliceSquare, ltBottomSliceSquare, ltDiagTopBevel,ltDiagBottomBevel, ltStarLine0, ltStarLine1, ltStarLine2, ltStarLine3, ltStarLine4, ltStarLine5 ); TSpinClickEvent = procedure(Sender : TObject; State : TOvcSpinState; Delta : Double; Wrap : Boolean) of object; type TOvcSpinner = class(TOvcCustomControl) protected {private} {property variables} FAcceleration : Integer; {value used to determine acceleration} FAutoRepeat : Boolean; {repeat if button held} FDelayTime : LongInt; FDelta : Double; {amount to change by} FRepeatCount : LongInt; FFocusedControl : TWinControl; {the control to give the focus to} FShowArrows : Boolean; FStyle : TOvcSpinnerStyle; FWrapMode : Boolean; {wrap at field bounderies} {events} FOnClick : TSpinClickEvent; {private instance variables} scNextMsgTime : LongInt; {regions for the five spin button sections} scUpRgn : hRgn; scDownRgn : hRgn; scLeftRgn : hRgn; scRightRgn : hRgn; scCenterRgn : hRgn; scCurrentState : TOvcSpinState; scLButton : Byte; scMouseOverBtn : Boolean; scPrevState : TOvcSpinState; scSizing : Boolean; scTopLeft, scTopRight, scBottomLeft, scBottomRight, scCenter : TPoint; scTopLeftCenter, scBottomLeftCenter, scTopRightCenter, scBottomRightCenter : TPoint; scTopMiddle, scBottomMiddle, scLeftMiddle, scRightMiddle : TPoint; scTopLeft4, scBottomLeft4, scTopRight4, scBottomRight4 : TPoint; {property methods} procedure SetAcceleration(const Value : Integer); procedure SetAutoRepeat(Value: Boolean); procedure SetShowArrows(const Value : Boolean); procedure SetStyle(Value : TOvcSpinnerStyle); {internal methods} function scCheckMousePos : TOvcSpinState; procedure scDeleteRegions; procedure scDoAutoRepeat; procedure scDrawArrow(const R: TRect; const Pressed: Boolean; const Direction: TOvcDirection); procedure scDrawLine(P1, P2 : TPoint; const Up : Boolean; LineType : TOvcSpinnerLineType); procedure scDrawNormalButton(const Redraw : Boolean); procedure scDrawFourWayButton(const Redraw : Boolean); procedure scDrawStarButton(const Redraw : Boolean); procedure scDrawDiagonalVertical(const Redraw : Boolean); procedure scDrawDiagonalHorizontal(const Redraw : Boolean); procedure scDrawDiagonalFourWay(const Redraw : Boolean); procedure scDrawPlainStar(const Redraw : Boolean); procedure scDrawButton(const Redraw : Boolean); procedure scInvalidateButton(const State : TOvcSpinState); procedure scPolyline(const Points: array of TPoint); {private message response methods} procedure OMRecreateWnd(var Msg : TMessage); message om_RecreateWnd; {windows message handling methods} procedure WMGetDlgCode(var Msg : TWMGetDlgCode); message WM_GETDLGCODE; procedure WMLButtonDown(var Msg : TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMLButtonUp(var Msg : TWMLButtonUp); message WM_LBUTTONUP; protected procedure CreateParams(var Params : TCreateParams); override; procedure Loaded; override; procedure Notification(AComponent : TComponent; Operation : TOperation); override; procedure Paint; override; {dynamic event wrappers} procedure DoOnClick(State : TOvcSpinState); dynamic; procedure scDoMouseDown(const XPos, YPos: Integer); virtual; procedure scDoMouseUp; virtual; procedure scUpdateNormalSizes; procedure scUpdateFourWaySizes; procedure scUpdateStarSizes; procedure scUpdateDiagonalVerticalSizes; procedure scUpdateDiagonalHorizontalSizes; procedure scUpdateDiagonalFourWaySizes; procedure scUpdatePlainStarSizes; procedure scUpdateSizes; virtual; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; property RepeatCount : LongInt read FRepeatCount; published {properties} property Acceleration : Integer read FAcceleration write SetAcceleration default 5; property AutoRepeat : Boolean read FAutoRepeat write SetAutoRepeat; property Delta : Double read FDelta write FDelta; property DelayTime : LongInt read FDelayTime write FDelayTime default 500; property FocusedControl : TWinControl read FFocusedControl write FFocusedControl; property ShowArrows : Boolean read FShowArrows write SetShowArrows default True; property Style : TOvcSpinnerStyle read FStyle write SetStyle default stNormalVertical; property WrapMode : Boolean read FWrapMode write FWrapMode default True; {inherited properties} {$IFDEF VERSION4} property Anchors; property Constraints; {$ENDIF} property Enabled; property ParentShowHint; property ShowHint; property Visible; {events} property OnClick : TSpinClickEvent read FOnClick write FOnClick; property OnMouseDown; property OnMouseMove; property OnMouseUp; end; implementation uses OvcEdCal, OvcEdTim; const scDefMinSize = 13; {$IFDEF NoAsm} function GetArrowWidth(Width, Height : Integer) : Integer; begin Result := Height; if Width < Height then Result := Width; Result := (Result SHR 1) OR 1; end; {$ELSE} function GetArrowWidth(Width, Height : Integer) : Integer; register; asm cmp eax, edx jle @@1 mov eax, edx @@1: shr eax, 1 or eax, 1 end; {$ENDIF} {*** TOvcSpinner ***} constructor TOvcSpinner.Create(AOwner: TComponent); begin inherited Create(AOwner); ControlStyle := ControlStyle + [csFramed, csOpaque]; ControlStyle := ControlStyle + [csReplicatable]; {initialize property variables} FAcceleration := 5; FAutoRepeat := True; FDelayTime := 500; FDelta := 1; FRepeatCount := 0; FShowArrows := True; FStyle := stNormalVertical; FWrapMode := True; Width := 16; Height := 25; TabStop := False; scCurrentState := ssNormal; scPrevState := ssNone; scMouseOverBtn := False; end; procedure TOvcSpinner.CreateParams(var Params : TCreateParams); begin inherited CreateParams(Params); ControlStyle := ControlStyle + [csOpaque] - [csFramed]; if not (csDesigning in ComponentState) then ControlStyle := ControlStyle - [csDoubleClicks]; end; destructor TOvcSpinner.Destroy; begin scDeleteRegions; inherited Destroy; end; procedure TOvcSpinner.DoOnClick(State : TOvcSpinState); var D : Double; begin if Assigned(FOnClick) or (Assigned(FFocusedControl) and ((FFocusedControl is TOvcBaseEntryField) or (FFocusedControl is TCustomEdit))) then begin if scMouseOverBtn then begin if LongInt(GetTickCount) > scNextMsgTime then begin {auto link with Orpheus entry fields} if Assigned(FFocusedControl) and (FFocusedControl is TOvcBaseEntryField) then begin case State of ssUpBtn : TOvcBaseEntryField(FFocusedControl).IncreaseValue(FWrapMode, Delta); ssDownBtn : TOvcBaseEntryField(FFocusedControl).DecreaseValue(FWrapMode, Delta); ssLeftBtn : TOvcBaseEntryField(FFocusedControl).MoveCaret(-1); ssRightBtn : TOvcBaseEntryField(FFocusedControl).MoveCaret(+1); end; end; {auto link with TCustomEdit controls} if Assigned(FFocusedControl) and (FFocusedControl is TCustomEdit) then begin try if (FFocusedControl is TOvcCustomDateEdit) then D := TOvcCustomDateEdit(FFocusedControl).Date else if (FFocusedControl is TOvcCustomTimeEdit) then D := TOvcCustomTimeEdit(FFocusedControl).AsMinutes else D := StrToFloat(TCustomEdit(FFocusedControl).Text); case State of ssUpBtn : D := D + Delta; ssDownBtn : D := D - Delta; end; if (FFocusedControl is TOvcCustomDateEdit) then TOvcCustomDateEdit(FFocusedControl).Date := D else if (FFocusedControl is TOvcCustomTimeEdit) then TOvcCustomTimeEdit(FFocusedControl).AsMinutes := trunc(D) else TCustomEdit(FFocusedControl).Text := FloatToStr(D); except end; end; {call OnClick event handler, if assigned} if Assigned(FOnClick) then FOnClick(Self, State, Delta, FWrapMode); {setup for next time} scNextMsgTime := LongInt(GetTickCount) + DelayTime - Acceleration*10*FRepeatCount; Inc(FRepeatCount); end; end; end; end; procedure TOvcSpinner.Loaded; begin inherited Loaded; scUpdateSizes; end; procedure TOvcSpinner.Notification(AComponent : TComponent; Operation : TOperation); begin inherited Notification(AComponent, Operation); if (AComponent = FFocusedControl) and (Operation = opRemove) then FocusedControl := nil; end; procedure TOvcSpinner.OMRecreateWnd(var Msg : TMessage); begin {$IFNDEF LCL} RecreateWnd; {$ELSE} MyMisc.RecreateWnd(Self); {$ENDIF} end; function TOvcSpinner.scCheckMousePos : TOvcSpinState; var P : TPoint; begin GetCursorPos(P); P := ScreenToClient(P); {see which button the mouse is over} Result := ssNone; if PtInRect(ClientRect, P) then begin {$IFDEF MSWINDOWS} if not (csClicked in ControlState) then {$ELSE} //csClicked not getting set with GTK if not (csLButtonDown in ControlState) then {$ENDIF} Result := ssNormal {mouse is over one of the buttons, which one?} else if (scUpRgn <> 0) and PtInRegion(scUpRgn, P.X, P.Y) then if (Style = stNormalHorizontal) then Result := ssRightBtn else Result := ssUpBtn else if (scDownRgn <> 0) and PtInRegion(scDownRgn, P.X, P.Y) then if (Style = stNormalHorizontal) then Result := ssLeftBtn else Result := ssDownBtn else if (scLeftRgn <> 0) and PtInRegion(scLeftRgn, P.X, P.Y) then Result := ssLeftBtn else if (scRightRgn <> 0) and PtInRegion(scRightRgn, P.X, P.Y) then Result := ssRightBtn else if (scCenterRgn <> 0) and PtInRegion(scCenterRgn, P.X, P.Y) then Result := ssCenterBtn else Result := ssNormal; end; end; procedure TOvcSpinner.scDeleteRegions; begin if scUpRgn <> 0 then begin DeleteObject(scUpRgn); scUpRgn := 0; end; if scDownRgn <> 0 then begin DeleteObject(scDownRgn); scDownRgn := 0; end; if scLeftRgn <> 0 then begin DeleteObject(scLeftRgn); scLeftRgn := 0; end; if scRightRgn <> 0 then begin DeleteObject(scRightRgn); scRightRgn := 0; end; if scCenterRgn <> 0 then begin DeleteObject(scCenterRgn); scCenterRgn := 0; end; end; procedure TOvcSpinner.scDoAutoRepeat; var NewState : TOvcSpinState; begin DoOnClick(scCurrentState); {don't auto-repeat for center button} if (scCurrentState = ssCenterBtn) or (not AutoRepeat) then begin repeat {allow other messages} Application.ProcessMessages; {until the mouse button is released} {$IFDEF MSWINDOWS} until ({$IFNDEF LCL} GetAsyncKeyState(scLButton) {$ELSE} GetKeyState(scLButton) {$ENDIF} and $8000) = 0; {$ELSE} //GTK GetKeyState returns 0 until not (csLButtonDown in ControlState); {$ENDIF} scDoMouseUp; Exit; end; {repeat until left button released} repeat if AutoRepeat then DoOnClick(scCurrentState); {allow other messages} Application.ProcessMessages; {get new button/mouse state} NewState := scCheckMousePos; {has anything changed} if NewState <> scCurrentState then begin {the mouse is not over a button or its over a new one} scPrevState := scCurrentState; scCurrentState := NewState; {don't depress the center button if the mouse moves over it} if NewState = ssCenterBtn then scCurrentState := ssNormal; scMouseOverBtn := not (scCurrentState in [ssNone, ssNormal]); scInvalidateButton(scPrevState); scInvalidateButton(scCurrentState); end; {until the mouse button is released} {$IFDEF MSWINDOWS} until ({$IFNDEF LCL} GetAsyncKeyState(scLButton) {$ELSE} GetKeyState(scLButton) {$ENDIF} and $8000) = 0; {$ELSE} //GTK GetKeyState returns 0 until not (csLButtonDown in ControlState); {$ENDIF} scDoMouseUp; end; procedure TOvcSpinner.scDoMouseDown(const XPos, YPos: Integer); begin scPrevState := scCurrentState; {find which button was clicked} scCurrentState := scCheckMousePos; scMouseOverBtn := True; scInvalidateButton(scPrevState); scInvalidateButton(scCurrentState); {initialize and start repeating} FRepeatCount := 0; scLButton := GetLeftButton; scNextMsgTime := GetTickCount-1; scDoAutoRepeat; end; procedure TOvcSpinner.scDoMouseUp; begin {save last state and redraw} scPrevState := scCurrentState; scCurrentState := ssNormal; scMouseOverBtn := False; scInvalidateButton(scPrevState); scInvalidateButton(scCurrentState); scDrawButton(False); end; procedure TOvcSpinner.scDrawArrow(const R: TRect; const Pressed: Boolean; const Direction: TOvcDirection); var ArrowWidth, ArrowHeight : Integer; X, Y : Integer; LeftPoint, RightPoint, PointPoint : TPoint; PLeftPoint, PRightPoint, PPointPoint : TPoint; begin if not FShowArrows then Exit; with Canvas do begin ArrowWidth := GetArrowWidth(R.Right-R.Left, R.Bottom-R.Top); ArrowHeight := (ArrowWidth + 1) div 2; if Direction in [dUp, dDown] then begin X := (R.Right-R.Left-ArrowWidth) div 2; Y := (R.Bottom-R.Top-ArrowHeight) div 2; end else begin X := (R.Right-R.Left-ArrowHeight) div 2; Y := (R.Bottom-R.Top-ArrowWidth) div 2; end; case Direction of dUp : begin LeftPoint := Point(R.Left + X, Y + ArrowHeight + R.Top - 1); RightPoint := Point(R.Left + X + ArrowWidth - 1, Y + ArrowHeight + R.Top -1 ); PointPoint := Point(R.Left + X + (ArrowWidth div 2), Y + R.Top); end; dDown : begin LeftPoint := Point(R.Left + X, Y + R.Top); RightPoint := Point(R.Left + X + ArrowWidth - 1 , Y + R.Top); PointPoint := Point(R.Left + X + (ArrowWidth div 2), Y + ArrowHeight + R.Top - 1); end; dRight : begin LeftPoint := Point(R.Left + X, Y + R.Top); RightPoint := Point(R.Left + X, Y + ArrowWidth + R.Top - 1); PointPoint := Point(R.Left + X + ArrowHeight - 1, Y + (ArrowWidth div 2) + R.Top); end; dLeft : begin LeftPoint := Point(R.Left + X + ArrowHeight - 1, Y + R.Top); RightPoint := Point(R.Left + X + ArrowHeight - 1, Y + ArrowWidth - 1 + R.Top); PointPoint := Point(R.Left + X, Y + (ArrowWidth div 2) + R.Top); end; end; PLeftPoint.X := LeftPoint.X + 1; PLeftPoint.Y := LeftPoint.Y + 1; PRightPoint.X := RightPoint.X + 1; PRightPoint.Y := RightPoint.Y + 1; PPointPoint.X := PointPoint.X + 1; PPointPoint.Y := PointPoint.Y + 1; if Pressed then begin Pen.Color := clBtnFace; Brush.Color := clBtnFace; Polygon([LeftPoint, RightPoint, PointPoint]); Pen.Color := clBtnText; Brush.Color := clBtnText; Polygon([PLeftPoint, PRightPoint, PPointPoint]); end else begin Pen.Color := clBtnFace; Brush.Color := clBtnFace; Polygon([PLeftPoint, PRightPoint, PPointPoint]); Pen.Color := clBtnText; Brush.Color := clBtnText; Polygon([LeftPoint, RightPoint, PointPoint]); end; end; end; procedure TOvcSpinner.scDrawButton(const Redraw : Boolean); begin case FStyle of stDiagonalFourWay : scDrawDiagonalFourWay(Redraw); stDiagonalHorizontal : scDrawDiagonalHorizontal(Redraw); stDiagonalVertical : scDrawDiagonalVertical(Redraw); stFourWay : scDrawFourWayButton(Redraw); stNormalHorizontal : scDrawNormalButton(Redraw); stNormalVertical : scDrawNormalButton(Redraw); stPlainStar : scDrawPlainStar(Redraw); stStar : scDrawStarButton(Redraw); end; end; procedure TOvcSpinner.scDrawDiagonalFourWay(const Redraw : Boolean); procedure DrawBasicShape; begin with Canvas do begin Brush.Color := clBtnFace; Brush.Style := bsSolid; Pen.Color := clBtnFace; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); scDrawLine(scBottomLeft4, scTopRight4, True, ltSingle); scDrawLine(scBottomLeft, scTopLeft, True, ltTopBevel); scDrawLine(scTopLeft, scTopRight, True, ltTopBevel); scDrawLine(scBottomLeft, scBottomRight, True, ltBottomBevel); scDrawLine(scBottomRight, scTopRight, True, ltBottomBevel); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssUpBtn : begin scDrawArrow(Rect(Width Div 4, 0, Width Div 2, Height div 2), not(Up), dUp); scDrawLine(scTopLeft4, scTopRight4, Up, ltTopBevel); scDrawLine(scTopLeft4, scBottomLeft4, Up, ltDiagTopBevel); scDrawLine(scBottomLeft4, scTopRight4, Up, ltBottomSlice); end; ssDownBtn : begin scDrawArrow(Rect(Width Div 2, (Height+1) div 2, Width * 3 Div 4, Height), not(Up), dDown); scDrawLine(scBottomRight4, scBottomLeft4, Up, ltBottomBevel); scDrawLine(scTopRight4, scBottomRight4, Up, ltDiagBottomBevel); scDrawLine(scBottomLeft4, scTopRight4, Up, ltTopSlice); end; ssLeftBtn : begin scDrawArrow(Rect(0, 0, Width Div 4, Height), not(Up), dLeft); scDrawLine(scTopLeft, scTopLeft4, Up, ltTopBevel); scDrawLine(scTopLeft, scBottomLeft, Up, ltTopBevel); scDrawLine(scTopLeft4, scBottomLeft4, Up, ltBottomBevel); scDrawLine(scBottomLeft, scBottomLeft4, Up, ltBottomBevel); end; ssRightBtn : begin scDrawArrow(Rect(Width * 3 Div 4, 0, Width, Height), not(Up), dRight); scDrawLine(scTopRight4, scTopRight, Up, ltTopBevel); scDrawLine(scTopRight4, scBottomRight4, Up, ltTopBevel); scDrawLine(scTopRight, scBottomRight, Up, ltBottomBevel); scDrawLine(scBottomRight4, scBottomRight, Up, ltBottomBevel); end; end; end; end; begin with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssUpBtn, True); DrawFace(ssDownBtn, True); DrawFace(ssLeftBtn, True); DrawFace(ssRightBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scDrawDiagonalHorizontal(const Redraw : Boolean); procedure DrawBasicShape; begin with Canvas do begin Brush.Color := clBtnFace; Brush.Style := bsSolid; Pen.Color := clBtnFace; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); scDrawLine(scBottomLeft, scTopRight, True, ltSingle); scDrawLine(scBottomLeft, scTopLeft, True, ltTopBevel); scDrawLine(scTopLeft, scTopRight, True, ltTopBevel); scDrawLine(scBottomLeft, scBottomRight, True, ltBottomBevel); scDrawLine(scBottomRight, scTopRight, True, ltBottomBevel); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssLeftBtn : begin scDrawArrow(Rect(0, 0, Width div 2, (Height div 2)), not(Up), dLeft); scDrawLine(scTopLeft, scTopRight, Up, ltTopBevel); scDrawLine(scTopLeft, scBottomLeft, Up, ltTopBevel); scDrawLine(scBottomLeft, scTopRight, Up, ltBottomSlice); end; ssRightBtn : begin scDrawArrow(Rect((Width+1) div 2, (Height+1) div 2, Width, Height), not(Up), dRight); scDrawLine(scBottomLeft, scBottomRight, Up, ltBottomBevel); scDrawLine(scTopRight, scBottomRight, Up, ltBottomBevel); scDrawLine(scBottomLeft, scTopRight, Up, ltTopSlice); end; end; end; end; begin with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssLeftBtn, True); DrawFace(ssRightBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scDrawDiagonalVertical(const Redraw : Boolean); procedure DrawBasicShape; begin with Canvas do begin Brush.Color := clBtnFace; Brush.Style := bsSolid; Pen.Color := clBtnFace; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); scDrawLine(scBottomLeft, scTopRight, True, ltSingle); scDrawLine(scBottomLeft, scTopLeft, True, ltTopBevel); scDrawLine(scTopLeft, scTopRight, True, ltTopBevel); scDrawLine(scBottomLeft, scBottomRight, True, ltBottomBevel); scDrawLine(scBottomRight, scTopRight, True, ltBottomBevel); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssUpBtn : begin scDrawArrow(Rect(0, 0, Width div 2, (Height div 2)), not(Up), dUp); scDrawLine(scTopLeft, scTopRight, Up, ltTopBevel); scDrawLine(scTopLeft, scBottomLeft, Up, ltTopBevel); scDrawLine(scBottomLeft, scTopRight, Up, ltBottomSlice); end; ssDownBtn : begin scDrawArrow(Rect((Width+1) div 2, (Height+1) div 2, Width, Height), not(Up), dDown); scDrawLine(scBottomLeft, scBottomRight, Up, ltBottomBevel); scDrawLine(scTopRight, scBottomRight, Up, ltBottomBevel); scDrawLine(scBottomLeft, scTopRight, Up, ltTopSlice); end; end; end; end; begin with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssUpBtn, True); DrawFace(ssDownBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scDrawFourWayButton(const Redraw : Boolean); procedure DrawBasicShape; begin with Canvas do begin Brush.Color := clBtnFace; Brush.Style := bsSolid; Pen.Color := clBtnFace; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); scDrawLine(scTopLeft, scBottomRight, True, ltSingle); scDrawLine(scBottomLeft, scTopRight, True, ltSingle); scDrawLine(scBottomLeft, scTopLeft, True, ltTopBevel); scDrawLine(scTopLeft, scTopRight, True, ltTopBevel); scDrawLine(scBottomLeft, scBottomRight, True, ltBottomBevel); scDrawLine(scBottomRight, scTopRight, True, ltBottomBevel); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssUpBtn : begin scDrawArrow(Rect(0, 0, Width, (Height div 3)), not(Up), dUp); scDrawLine(scTopLeft, scTopRight, Up, ltTopBevel); scDrawLine(scTopRight, scCenter, Up, ltBottomSliceSquare); scDrawLine(scTopLeft, scCenter, Up, ltBottomSliceSquare); end; ssDownBtn : begin scDrawArrow(Rect(0, Height - (Height div 3), Width, Height), not(Up), dDown); scDrawLine(scBottomLeft, scBottomRight, Up, ltBottomBevel); scDrawLine(scBottomLeft, scCenter, Up, ltTopSliceSquare); scDrawLine(scBottomRight, scCenter, Up, ltTopSliceSquare); end; ssLeftBtn : begin scDrawArrow(Rect(0, 0, (Width div 3), Height), not(Up), dLeft); scDrawLine(scTopLeft, scBottomLeft, Up, ltTopBevel); scDrawLine(scBottomLeft, scCenter, Up, ltBottomSliceSquare); scDrawLine(scTopLeft, scCenter, Up, ltTopSliceSquare); end; ssRightBtn : begin scDrawArrow(Rect(Width - (Width div 3), 0, Width, Height), not(Up), dRight); scDrawLine(scTopRight, scBottomRight, Up, ltBottomBevel); scDrawLine(scTopRight, scCenter, Up, ltTopSliceSquare); scDrawLine(scBottomRight, scCenter, Up, ltBottomSliceSquare); end; end; end; end; begin with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssUpBtn, True); DrawFace(ssDownBtn, True); DrawFace(ssLeftBtn, True); DrawFace(ssRightBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scDrawLine(P1, P2 : TPoint; const Up : Boolean; LineType : TOvcSpinnerLineType); {-this routine draws a parallel line} {The Offset is required because of the nature of Bressenham's algorithm} {Negative Offsets are above the line, and Positive Offsets are Below} function GetSlope(const P1, P2 : TPoint) : Extended; var dX, dY : Integer; begin dY := (P1.y - P2.y); dX := (P1.x - P2.x); if (dX = 0) then if dY > 0 then Result := 999999.0 else Result := -999999.0 else Result := dY / dX; end; procedure DrawLine(P1, P2 : TPoint; Offset : Integer; const Square : Boolean); var Slope : Extended; P : TPoint; P1Square, P2Square : Boolean; begin P2Square := Square; P1Square := False; if P1.x > P2.X then begin P := P1; P1 := P2; P2 := P; P2Square := False; P1Square := Square; end; Slope := GetSlope(P1, P2); if Slope >= 0 then begin if P1.x > scTopMiddle.x then Offset := -Offset; end; if abs(Slope) <= 1 then begin if Slope = 0 then begin P1.y := P1.y + Offset; P2.y := P2.y + Offset; {these are to shorten the lines a little} P1.X := P1.X - Abs(Offset); P2.X := P2.X + Abs(Offset); end else if (Slope = 1) and (Offset > 0) then begin if P1Square then begin P1.X := P1.X + 0 * Abs(Offset); P1.y := P1.y + 1 * Abs(Offset); end else begin P1.X := P1.X + 2 * Abs(Offset); P1.y := P1.y + 3 * Abs(Offset); end; if P2Square then begin P2.X := P2.X - 1 * Abs(Offset); P2.y := P2.y - 0 * Abs(Offset); end else begin P2.X := P2.X - 3 * Abs(Offset); P2.y := P2.y - 2 * Abs(Offset); end; end else if (Slope = 1) and (Offset < 0) then begin if P1Square then begin P1.X := P1.X + 1 * Abs(Offset); P1.y := P1.y + 0 * Abs(Offset); end else begin P1.X := P1.X + 3 * Abs(Offset); P1.y := P1.y + 2 * Abs(Offset); end; if P2Square then begin P2.X := P2.X - 0 * Abs(Offset); P2.y := P2.y - 1 * Abs(Offset); end else begin P2.X := P2.X - 2 * Abs(Offset); P2.y := P2.y - 3 * Abs(Offset); end; end else if (Slope = -1) and (Offset > 0) then begin if P1Square then begin P1.X := P1.X + 1 * Abs(Offset); P1.y := P1.y - 0 * Abs(Offset); end else begin P1.X := P1.X + 3 * Abs(Offset); P1.y := P1.y - 2 * Abs(Offset); end; if P2Square then begin P2.X := P2.X - 0 * Abs(Offset); P2.y := P2.y + 1 * Abs(Offset); end else begin P2.X := P2.X - 2 * Abs(Offset); P2.y := P2.y + 3 * Abs(Offset); end; end else if (Slope = -1) and (Offset < 0) then begin if P1Square then begin P1.X := P1.X + 0 * Abs(Offset); P1.y := P1.y - 1 * Abs(Offset); end else begin P1.X := P1.X + 2 * Abs(Offset); P1.y := P1.y - 3 * Abs(Offset); end; if P2Square then begin P2.X := P2.X - 1 * Abs(Offset); P2.y := P2.y + 0 * Abs(Offset); end else begin P2.X := P2.X - 3 * Abs(Offset); P2.y := P2.y + 2 * Abs(Offset); end; end else begin P1.y := P1.y + Offset; P2.y := P2.y + Offset; end; end else begin P1.x := P1.x + Offset; P2.x := P2.x + Offset; if ((P1.x - P2.x) = 0) then begin {These are to shorten the lines a little} if (P1.y - P2.y) > 0 then begin P1.Y := P1.Y - Abs(Offset); P2.Y := P2.Y + Abs(Offset); end else begin P1.Y := P1.Y + Abs(Offset); P2.Y := P2.Y - Abs(Offset); end; end; end; scPolyLine([P1, P2]); end; const BtnColor : array[Boolean, 0..7] of TColor = ( (clBtnShadow, clBtnShadow, clBtnFace, clBtnHighlight, clWindowFrame, clBtnHighLight, clRed, clWindowFrame), (clBtnHighlight, clBtnFace, clBtnShadow, clWindowFrame, clBtnHighlight, clBtnFace, clGreen, clWindowFrame)); SpinnerLines : array[TOvcSpinnerLineType, 0..1] of -1..7 = ( (7, -1), {ltSingle} (4, 1), {ltTopBevel} (3, 2), {ltBottomBevel} (4, 7), {ltTopSlice} (3, 7), {ltBottomSlice} (4, 7), {ltTopSliceSquare} (3, 7), {ltBottomSliceSquare} (4, 1), {ltDiagTopBevel} (3, 2), {ltDiagBottomBevel} (0, -1), {ltStarLine0} (3, -1), {ltStarLine1} (4, 1), {ltStarLine2} (3, 2), {ltStarLine3} (4, 7), {ltStarLine4} (2, 7) {ltStarLine5} ); {ComplementLine is used for shading the Left/Right Lines} ComplementLine : array[TOvcSpinnerLineType] of TOvcSpinnerLineType = ( ltSingle, {ltSingle} ltTopBevel, {ltTopBevel} ltBottomBevel, {ltBottomBevel} ltBottomSlice, {ltTopSlice} ltTopSlice, {ltBottomSlice} ltBottomSliceSquare, {ltTopSliceSquare} ltTopSliceSquare, {ltBottomSliceSquare} ltDiagBottomBevel, {ltDiagTopBevel} ltDiagTopBevel, {ltDiagBottomBevel} ltStarLine1, {ltStarLine0} ltStarLine0, {ltStarLine1} ltStarLine3, {ltStarLine2} ltStarLine2, {ltStarLine3} ltStarLine5, {ltStarLine4} ltStarLine4 {ltStarLine5} ); var DrawSquare : Boolean; Offset : Integer; begin with Canvas do begin {if the line is on the other side then ComplementLine} if (GetSlope(P1, P2) > 1) then linetype := ComplementLine[LineType]; Pen.Color := BtnColor[Up, SpinnerLines[LineType, 0]]; DrawSquare := False; Offset := 0; case LineType of ltTopSlice : begin Offset := 1; end; ltBottomSlice : begin Offset := -1; end; ltTopSliceSquare : begin DrawSquare := True; Offset := 1; end; ltBottomSliceSquare : begin DrawSquare := True; Offset := -1; end; ltDiagTopBevel : begin Offset := 1; end; ltDiagBottomBevel : begin Offset := -1; end; ltStarLine2 : begin if P1.X = P2.X then begin Inc(P1.X);Inc(P1.y);Inc(P2.X);Dec(P2.y); end else begin Inc(P1.X);Inc(P1.y);Dec(P2.X);Inc(P2.y); end; end; ltStarLine3 : begin if P1.X = P2.X then begin Dec(P1.X);Inc(P1.y);Dec(P2.X);Dec(P2.y); end else begin Inc(P1.X);Dec(P1.y);Dec(P2.X);Dec(P2.y); end; end; ltStarLine4 : begin DrawSquare := True; Offset := 1; end; ltStarLine5 : begin DrawSquare := True; Offset := -1; end; end; DrawLine(P1, P2, Offset, DrawSquare); if SpinnerLines[LineType, 1] = -1 then Exit; Pen.Color := BtnColor[Up, SpinnerLines[LineType, 1]]; DrawSquare := False; Offset := 0; case LineType of ltTopBevel : begin Offset := 1; end; ltBottomBevel : begin Offset := -1; end; ltTopSliceSquare : begin DrawSquare := True; end; ltBottomSliceSquare : begin DrawSquare := True; end; ltDiagTopBevel : begin Offset := 2; end; ltDiagBottomBevel : begin Offset := -2; end; ltStarLine2 : begin if P1.X = P2.X then begin Inc(P1.X);Inc(P1.y);Inc(P2.X);Dec(P2.y); end else begin Inc(P1.X);Inc(P1.y);Dec(P2.X);Inc(P2.y); end; end; ltStarLine3 : begin if P1.X = P2.X then begin Dec(P1.X);Inc(P1.y);Dec(P2.X);Dec(P2.y); end else begin Inc(P1.X);Dec(P1.y);Dec(P2.X);Dec(P2.y); end; end; end; DrawLine(P1, P2, Offset, DrawSquare); end; end; procedure TOvcSpinner.scDrawNormalButton(const Redraw : Boolean); var TopPressed : Boolean; BottomPressed : Boolean; UpRect : TRect; DownRect : TRect; begin {$IFDEF MSWINDOWS} if (csClicked in ControlState) and scMouseOverBtn then begin {$ELSE} //csClicked not getting set with GTK if (csLButtonDown in ControlState) and scMouseOverBtn then begin {$ENDIF} TopPressed := (scCurrentState in [ssUpBtn, ssRightBtn]); BottomPressed := (scCurrentState in [ssDownBtn, ssLeftBtn]); end else begin TopPressed := False; BottomPressed := False; end; {$IFNDEF LCL} GetRgnBox(scUpRgn, UpRect); GetRgnBox(scDownRgn, DownRect); {$ELSE} MyMisc.GetRgnBox(scUpRgn, @UpRect); MyMisc.GetRgnBox(scDownRgn, @DownRect); {$ENDIF} if FStyle = stNormalVertical then begin Inc(UpRect.Right); Inc(UpRect.Bottom); Inc(DownRect.Top); end else begin Inc(UpRect.Bottom); Dec(DownRect.Right); end; Inc(DownRect.Bottom); Inc(DownRect.Right); DrawButtonFace(Canvas, UpRect, 1, bsNew, False, TopPressed, False); DrawButtonFace(Canvas, DownRect, 1, bsNew, False, BottomPressed, False); if FStyle = stNormalVertical then begin scDrawArrow(UpRect, TopPressed, dUp); scDrawArrow(DownRect, BottomPressed, dDown); end else begin scDrawArrow(UpRect, TopPressed, dRight); scDrawArrow(DownRect, BottomPressed, dLeft); end; end; procedure TOvcSpinner.scDrawPlainStar(const Redraw : Boolean); var PC : TColor; procedure DrawBasicShape; begin with Canvas do begin Pen.Color := clWindowFrame; Brush.Color := PC; Brush.Style := bsSolid; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssUpBtn : begin scDrawArrow(Rect(scTopLeftCenter.X, scTopMiddle.Y, scTopRightCenter.X, scCenter.Y), not(Up), dUp); scDrawLine(scTopMiddle, scTopRightCenter, Up, ltStarLine0); scDrawLine(scTopRightCenter, scCenter, Up, ltStarLine5); scDrawLine(scCenter, scTopLeftCenter, Up, ltStarLine5); scDrawLine(scTopMiddle, scTopLeftCenter, Up, ltStarLine0); end; ssDownBtn : begin scDrawArrow(Rect(scBottomLeftCenter.X, scCenter.Y, scBottomRightCenter.X, scBottomMiddle.Y), not(Up), dDown); scDrawLine(scBottomMiddle, scBottomLeftCenter, Up, ltStarLine1); scDrawLine(scCenter, scBottomLeftCenter, Up, ltStarLine4); scDrawLine(scBottomRightCenter, scCenter, Up, ltStarLine4); scDrawLine(scBottomMiddle, scBottomRightCenter, Up, ltStarLine1); end; ssLeftBtn : begin scDrawArrow(Rect(scLeftMiddle.X, scTopLeftCenter.Y, scCenter.X, scBottomLeftCenter.Y), not(Up), dLeft); scDrawLine(scLeftMiddle, scTopLeftCenter, Up, ltStarLine0); scDrawLine(scTopLeftCenter, scCenter, Up, ltStarLine4); scDrawLine(scCenter, scBottomLeftCenter, Up, ltStarLine5); scDrawLine(scBottomLeftCenter, scLeftMiddle, Up, ltStarLine1); end; ssRightBtn : begin scDrawArrow(Rect(scCenter.X, scTopRightCenter.Y, scRightMiddle.X, scBottomRightCenter.Y),not(Up), dRight); scDrawLine(scCenter, scTopRightCenter, Up, ltStarLine4); scDrawLine(scTopRightCenter, scRightMiddle, Up, ltStarLine0); scDrawLine(scRightMiddle, scBottomRightCenter, Up, ltStarLine1); scDrawLine(scBottomRightCenter, scCenter, Up, ltStarLine5); end; end; end; end; begin {get current parent color} {$IFDEF VERSION5} if (Parent is TCustomForm) then PC := TForm(Parent).Color else if (Parent is TCustomFrame) then PC := TFrame(Parent).Color {$ELSE} if Parent is TForm then PC := TForm(Parent).Color {$ENDIF} else PC := Color; with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssUpBtn, True); DrawFace(ssDownBtn, True); DrawFace(ssLeftBtn, True); DrawFace(ssRightBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scDrawStarButton(const Redraw : Boolean); var PC : TColor; procedure DrawBasicShape; begin with Canvas do begin Pen.Color := clWindowFrame; Brush.Color := PC; Brush.Style := bsSolid; FillRect(Rect(scTopLeft.X, scTopLeft.Y, scBottomRight.X, scBottomRight.Y)); end; end; procedure DrawFace(State : TOvcSpinState; Up : Boolean); begin with Canvas do begin case State of ssUpBtn : begin scDrawArrow(Rect(scTopLeftCenter.X, scTopMiddle.Y, scTopRightCenter.X, scTopLeftCenter.Y), not(Up), dUp); scDrawLine(scTopMiddle, scTopRightCenter, Up, ltStarLine0); scDrawLine(scTopRightCenter, scTopLeftCenter, Up, ltStarLine1); scDrawLine(scTopMiddle, scTopLeftCenter, Up, ltStarLine0); end; ssDownBtn : begin scDrawArrow(Rect(scBottomLeftCenter.X, scBottomLeftCenter.Y, scBottomRightCenter.X, scBottomMiddle.Y),not(Up), dDown); scDrawLine(scBottomMiddle, scBottomLeftCenter, Up, ltStarLine1); scDrawLine(scBottomRightCenter, scBottomLeftCenter, Up, ltStarLine0); scDrawLine(scBottomMiddle, scBottomRightCenter, Up, ltStarLine1); end; ssLeftBtn : begin scDrawArrow(Rect(scLeftMiddle.X, scTopLeftCenter.Y, scTopLeftCenter.X, scBottomLeftCenter.Y), not(Up), dLeft); scDrawLine(scLeftMiddle, scTopLeftCenter, Up, ltStarLine0); scDrawLine(scTopLeftCenter, scBottomLeftCenter, Up, ltStarLine1); scDrawLine(scBottomLeftCenter, scLeftMiddle, Up, ltStarLine1); end; ssRightBtn : begin scDrawArrow(Rect(scTopRightCenter.X, scTopRightCenter.Y, scRightMiddle.X, scBottomRightCenter.Y), not(Up), dRight); scDrawLine(scTopRightCenter, scBottomRightCenter, Up, ltStarLine0); scDrawLine(scRightMiddle, scTopRightCenter, Up, ltStarLine0); scDrawLine(scBottomRightCenter, scRightMiddle, Up, ltStarLine1); end; ssCenterBtn : begin scDrawLine(scTopLeftCenter, scTopRightCenter, Up, ltStarLine2); scDrawLine(scTopLeftCenter, scBottomLeftCenter, Up, ltStarLine2); scDrawLine(scTopRightCenter, scBottomRightCenter, Up, ltStarLine3); scDrawLine(scBottomLeftCenter, scBottomRightCenter, Up, ltStarLine3); end; end; end; end; begin {get current parent color} {$IFDEF VERSION5} if (Parent is TCustomForm) then PC := TForm(Parent).Color else if (Parent is TCustomFrame) then PC := TFrame(Parent).Color {$ELSE} if Parent is TForm then PC := TForm(Parent).Color {$ENDIF} else PC := Color; with Canvas do begin if Redraw then begin DrawBasicShape; DrawFace(ssUpBtn, True); DrawFace(ssDownBtn, True); DrawFace(ssLeftBtn, True); DrawFace(ssRightBtn, True); DrawFace(ssCenterBtn, True); end; if scPrevState <> scCurrentState then DrawFace(scPrevState, True); if scMouseOverBtn then DrawFace(scCurrentState, False); end; end; procedure TOvcSpinner.scInvalidateButton(const State : TOvcSpinState); begin case State of ssUpBtn : InvalidateRgn(Handle, scUpRgn, False); ssDownBtn : InvalidateRgn(Handle, scDownRgn, False); ssLeftBtn : InvalidateRgn(Handle, scLeftRgn, False); ssRightBtn : InvalidateRgn(Handle, scRightRgn, False); ssCenterBtn : InvalidateRgn(Handle, scCenterRgn, False); end; end; procedure TOvcSpinner.scPolyline(const Points: array of TPoint); begin Canvas.Polyline(Points); with Points[High(Points)] do Canvas.Pixels[X,Y] := Canvas.Pen.Color; end; procedure TOvcSpinner.scUpdateNormalSizes; var scHeight : Integer; {Height of client area} scWidth : Integer; {Width of client area} begin {get size of client area} scWidth := scBottomRight.X; scHeight := scBottomRight.Y; {setup the TRect structures with new sizes} if FStyle = stNormalVertical then begin scUpRgn := CreateRectRgn(0, 0, scWidth, scHeight div 2); scDownRgn := CreateRectRgn(0, scHeight div 2, scWidth, scHeight); end else begin scUpRgn := CreateRectRgn(scWidth div 2, 0, scWidth, scHeight); scDownRgn := CreateRectRgn(0, 0, scWidth div 2, scHeight); end; end; procedure TOvcSpinner.scUpdateFourWaySizes; var Points : array[0..2] of TPoint; begin Points[0] := scTopLeft; Points[1] := scTopRight; Points[2] := scCenter; scUpRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scBottomLeft; Points[1] := scCenter; Points[2] := scBottomRight; scDownRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scTopLeft; Points[1] := scCenter; Points[2] := scBottomLeft; scLeftRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scTopRight; Points[1] := scBottomRight; Points[2] := scCenter; scRightRgn := CreatePolygonRgn(Points, 3, ALTERNATE); end; procedure TOvcSpinner.scUpdateStarSizes; var Points : array[0..3] of TPoint; begin {up} Points[0] := scTopMiddle; Points[1] := scTopRightCenter; Points[2] := scTopLeftCenter; scUpRgn := CreatePolygonRgn(Points, 3, ALTERNATE); {down} Points[0] := scBottomMiddle; Points[1] := scBottomLeftCenter; Points[2] := scBottomRightCenter; scDownRgn := CreatePolygonRgn(Points, 3, ALTERNATE); {left} Points[0] := scLeftMiddle; Points[1] := scTopLeftCenter; Points[2] := scBottomLeftCenter; scLeftRgn := CreatePolygonRgn(Points, 3, ALTERNATE); {right} Points[0] := scRightMiddle; Points[1] := scBottomRightCenter; Points[2] := scTopRightCenter; scRightRgn := CreatePolygonRgn(Points, 3, ALTERNATE); {center} Points[0] := scTopLeftCenter; Points[1] := scTopRightCenter; Points[2] := scBottomRightCenter; Points[3] := scBottomLeftCenter; scCenterRgn := CreatePolygonRgn(Points, 4, ALTERNATE); end; procedure TOvcSpinner.scUpdateDiagonalVerticalSizes; var Points : array[0..2] of TPoint; begin Points[0] := scTopLeft; Points[1] := scTopRight; Points[2] := scBottomLeft; scUpRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scBottomLeft; Points[1] := scTopRight; Points[2] := scBottomRight; scDownRgn := CreatePolygonRgn(Points, 3, ALTERNATE); end; procedure TOvcSpinner.scUpdateDiagonalHorizontalSizes; var Points : array[0..2] of TPoint; begin Points[0] := scTopLeft; Points[1] := scTopRight; Points[2] := scBottomLeft; scLeftRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scBottomLeft; Points[1] := scTopRight; Points[2] := scBottomRight; scRightRgn := CreatePolygonRgn(Points, 3, ALTERNATE); end; procedure TOvcSpinner.scUpdateDiagonalFourWaySizes; var Points : array[0..3] of TPoint; begin Points[0] := scTopLeft4; Points[1] := scTopRight4; Points[2] := scBottomLeft4; scUpRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scTopRight4; Points[1] := scBottomRight4; Points[2] := scBottomLeft4; scDownRgn := CreatePolygonRgn(Points, 3, ALTERNATE); Points[0] := scTopLeft; Points[1] := scTopLeft4; Points[2] := scBottomLeft4; Points[3] := scBottomLeft; scLeftRgn := CreatePolygonRgn(Points, 4, ALTERNATE); Points[0] := scTopRight4; Points[1] := scTopRight; Points[2] := scBottomRight; Points[3] := scBottomRight4; scRightRgn := CreatePolygonRgn(Points, 4, ALTERNATE); end; procedure TOvcSpinner.scUpdatePlainStarSizes; var Points : array[0..3] of TPoint; begin Points[0] := scTopMiddle; Points[1] := scTopRightCenter; Points[2] := scCenter; Points[3] := scTopLeftCenter; scUpRgn := CreatePolygonRgn(Points, 4, ALTERNATE); Points[0] := scBottomLeftCenter; Points[1] := scCenter; Points[2] := scBottomRightCenter; Points[3] := scBottomMiddle; scDownRgn := CreatePolygonRgn(Points, 4, ALTERNATE); Points[0] := scLeftMiddle; Points[1] := scTopLeftCenter; Points[2] := scCenter; Points[3] := scBottomLeftCenter; scLeftRgn := CreatePolygonRgn(Points, 4, ALTERNATE); Points[0] := scTopRightCenter; Points[1] := scRightMiddle; Points[2] := scBottomRightCenter; Points[3] := scCenter; scRightRgn := CreatePolygonRgn(Points, 4, ALTERNATE); end; procedure TOvcSpinner.scUpdateSizes; begin {store info about button locations} scDeleteRegions; case FStyle of stNormalVertical : scUpdateNormalSizes; stNormalHorizontal : scUpdateNormalSizes; stFourWay : scUpdateFourWaySizes; stStar : scUpdateStarSizes; stDiagonalVertical : scUpdateDiagonalVerticalSizes; stDiagonalHorizontal : scUpdateDiagonalHorizontalSizes; stDiagonalFourWay : scUpdateDiagonalFourWaySizes; stPlainStar : scUpdatePlainStarSizes; end; end; procedure TOvcSpinner.Paint; begin scDrawButton(True); end; procedure TOvcSpinner.SetAcceleration(const Value : Integer); begin if Value <= 10 then FAcceleration := Value; end; { - Added} procedure TOvcSpinner.SetAutoRepeat(Value: Boolean); begin FAutoRepeat := Value; if FAutoRepeat and not (csLoading in ComponentState) then scDoAutoRepeat; end; procedure TOvcSpinner.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); var L, T, H, W : Integer; begin if (csDesigning in ComponentState) and not (csLoading in ComponentState) then begin {limit smallest size} if AWidth < scDefMinSize then AWidth := scDefMinSize ; if AHeight < scDefMinSize then AHeight := scDefMinSize ; end; L := Left; T := Top; H := Height; W := Width; inherited SetBounds(ALeft, ATop, AWidth, AHeight); if (L <> Left) or (T <> Top) or (H <> Height) or (W <> Width) then begin scTopLeft := Point(0 , 0 ); scTopRight := Point(Width-1 , 0 ); scBottomLeft := Point(0 , Height-1); scBottomRight := Point(Width-1 , Height-1); scCenter := Point(Width div 2 , Height div 2 ); scTopLeftCenter := Point(Width * 1 div 3 , Height * 1 div 3 ); scBottomLeftCenter := Point(Width * 1 div 3 , Height * 2 div 3 ); scTopRightCenter := Point(Width * 2 div 3 , Height * 1 div 3 ); scBottomRightCenter:= Point(Width * 2 div 3 , Height * 2 div 3 ); scTopMiddle := Point(Width div 2 , 0 ); scBottomMiddle:= Point(Width div 2 , Height - 1 ); scLeftMiddle := Point(0 , Height div 2 ); scRightMiddle := Point(Width - 1 , Height div 2 ); scTopLeft4 := Point(Width div 4 , 0 ); scBottomLeft4 := Point(Width div 4 , Height - 1 ); scTopRight4 := Point(Width * 3 div 4, 0 ); scBottomRight4:= Point(Width * 3 div 4, Height - 1 ); end; {update sizes of control and button regions} scUpdateSizes; if HandleAllocated then Invalidate; end; procedure TOvcSpinner.SetShowArrows(const Value : Boolean); begin if Value <> FShowArrows then begin FShowArrows := Value; Invalidate; end; end; procedure TOvcSpinner.SetStyle(Value : TOvcSpinnerStyle); begin if Value <> FStyle then begin FStyle := Value; {$IFNDEF LCL} RecreateWnd; {$ELSE} MyMisc.RecreateWnd(Self); {$ENDIF} if not (csLoading in ComponentState) then SetBounds(Left, Top, Width, Height); {force resize} end; end; procedure TOvcSpinner.WMGetDlgCode(var Msg : TWMGetDlgCode); begin {tell windows we are a static control to avoid receiving the focus} Msg.Result := DLGC_STATIC; end; procedure TOvcSpinner.WMLButtonDown(var Msg : TWMLButtonDown); begin inherited; if Assigned(FFocusedControl) then begin if GetFocus <> FFocusedControl.Handle then begin {set focus to ourself to force field validation} SetFocus; {allow message processing} Application.ProcessMessages; {if we didn't keep the focus, something must have happened--exit} if (GetFocus <> Handle) then Exit; end; if GetFocus <> FFocusedControl.Handle then if FFocusedControl.CanFocus then FFocusedControl.SetFocus; end; try scDoMouseDown(Msg.XPos, Msg.YPos); except scDoMouseUp; raise; end; end; procedure TOvcSpinner.WMLButtonUp(var Msg : TWMLButtonUp); begin inherited; scDoMouseUp; end; end.