git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jvcl@12 7f62d464-2af8-f54e-996c-e91b33f51cbe
628 lines
16 KiB
ObjectPascal
628 lines
16 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
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/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: QToolWin.pas, released on 2004-05-16
|
|
|
|
The Initial Developer of the Original Code is Andreas Hausladen
|
|
[Andreas dott Hausladen att gmx dott de]
|
|
Copyright (C) 2004 Andreas Hausladen.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
|
|
Known Issues:
|
|
----------------------------------------------------------------------------}
|
|
// $Id: QComCtrlsEx.pas 11641 2007-12-24 16:34:00Z outchy $
|
|
|
|
unit QComCtrlsEx;
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, Contnrs, Types, Qt, QGraphics, QControls, QForms,
|
|
QStdCtrls, QExtCtrls, QComboEdits, QWindows;
|
|
|
|
type
|
|
TUDAlignButton = (udLeft, udRight);
|
|
TUDOrientation = (udHorizontal, udVertical);
|
|
TUDBtnType = (btNext, btPrev);
|
|
TUpDownDirection = (updNone, updUp, updDown);
|
|
TUDClickEvent = procedure (Sender: TObject; Button: TUDBtnType) of object;
|
|
TUDChangingEvent = procedure (Sender: TObject; var AllowChange: Boolean) of object;
|
|
TUDChangingEventEx = procedure (Sender: TObject; var AllowChange: Boolean;
|
|
NewValue: SmallInt; Direction: TUpDownDirection) of object;
|
|
|
|
TCustomUpDown = class(TCustomControl)
|
|
private
|
|
FArrowKeys: Boolean;
|
|
FAssociate: TWidgetControl;
|
|
FMin: SmallInt;
|
|
FMax: SmallInt;
|
|
FIncrement: Integer;
|
|
FNewValue: SmallInt;
|
|
FNewValueDelta: SmallInt;
|
|
FPosition: SmallInt;
|
|
FThousands: Boolean;
|
|
FWrap: Boolean;
|
|
FOnClick: TUDClickEvent;
|
|
FAlignButton: TUDAlignButton;
|
|
FOrientation: TUDOrientation;
|
|
FOnChanging: TUDChangingEvent;
|
|
FOnChangingEx: TUDChangingEventEx;
|
|
|
|
FButtonDown: Integer;
|
|
FMouseOverButton: Boolean;
|
|
FRepeatTimer: TTimer;
|
|
FForceAlign: Boolean;
|
|
|
|
procedure SetAssociate(Value: TWinControl);
|
|
function GetPosition: SmallInt;
|
|
procedure SetMin(Value: SmallInt);
|
|
procedure SetMax(Value: SmallInt);
|
|
procedure SetPosition(Value: SmallInt);
|
|
procedure SetAlignButton(Value: TUDAlignButton);
|
|
procedure SetOrientation(Value: TUDOrientation);
|
|
procedure SetArrowKeys(Value: Boolean);
|
|
procedure SetThousands(Value: Boolean);
|
|
function GetRepeatInterval: Integer;
|
|
procedure SetRepeatInterval(Value: Integer);
|
|
procedure SetForceAlign(const Value: Boolean);
|
|
protected
|
|
function AssociateHook(Sender: QObjectH; Event: QEventH): Boolean; virtual;
|
|
procedure Paint; override;
|
|
procedure UpdatePosition(Value: SmallInt); virtual;
|
|
procedure UpdateAlignment; virtual;
|
|
function ButtonRect(ButtonIndex: Integer): TRect; virtual;
|
|
procedure RepeatTimer(Sender: TObject); virtual;
|
|
procedure ChangePosition(ButtonIndex: Integer);
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X: Integer; Y: Integer); override;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer;
|
|
Y: Integer); override;
|
|
procedure BoundsChanged; override;
|
|
|
|
function DoCanChange(NewVal: SmallInt; Delta: SmallInt): Boolean; virtual;
|
|
function CanChange: Boolean; dynamic;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure Click(Button: TUDBtnType); reintroduce; dynamic;
|
|
property AlignButton: TUDAlignButton read FAlignButton write SetAlignButton default udRight;
|
|
property ArrowKeys: Boolean read FArrowKeys write SetArrowKeys default True;
|
|
property Associate: TWidgetControl read FAssociate write SetAssociate;
|
|
property Min: SmallInt read FMin write SetMin default 0;
|
|
property Max: SmallInt read FMax write SetMax default 100;
|
|
property Increment: Integer read FIncrement write FIncrement default 1;
|
|
property Orientation: TUDOrientation read FOrientation write SetOrientation default udVertical;
|
|
property Position: SmallInt read GetPosition write SetPosition default 0;
|
|
property Thousands: Boolean read FThousands write SetThousands default True;
|
|
property Wrap: Boolean read FWrap write FWrap default False;
|
|
property OnChanging: TUDChangingEvent read FOnChanging write FOnChanging;
|
|
property OnChangingEx: TUDChangingEventEx read FOnChangingEx write FOnChangingEx;
|
|
property OnClick: TUDClickEvent read FOnClick write FOnClick;
|
|
|
|
// exclusive for VisualCLX
|
|
property RepeatInterval: Integer read GetRepeatInterval write SetRepeatInterval default 125;
|
|
property ForceAlign: Boolean read FForceAlign write SetForceAlign default False;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
TUpDown = class(TCustomUpDown)
|
|
published
|
|
property AlignButton;
|
|
property Anchors;
|
|
property Associate;
|
|
property ArrowKeys;
|
|
property Enabled;
|
|
property Hint;
|
|
property Min;
|
|
property Max;
|
|
property Increment;
|
|
property Constraints;
|
|
property Orientation;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property Position;
|
|
property ShowHint;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Thousands;
|
|
property Visible;
|
|
property Wrap;
|
|
property OnChanging;
|
|
property OnChangingEx;
|
|
property OnContextPopup;
|
|
property OnClick;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math;
|
|
|
|
function ExcludeThousands(const Text: string): string;
|
|
var
|
|
Len, i: Integer;
|
|
begin
|
|
Result := Text;
|
|
Len := Length(Result);
|
|
if Len > 4 then
|
|
begin
|
|
i := Len - 3;
|
|
while (i > 1) do
|
|
begin
|
|
if Result[i] = ThousandSeparator then
|
|
Delete(Result, i, 1);
|
|
Dec(i, 2);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function IncludeThousands(const Text: string): string;
|
|
var
|
|
Len, i: Integer;
|
|
begin
|
|
Result := Text;
|
|
Len := Length(Result);
|
|
if Len > 3 then
|
|
begin
|
|
i := Len - 2;
|
|
while (i > 1) do
|
|
begin
|
|
Insert(ThousandSeparator, Result, i);
|
|
Dec(i, 3);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TCustomUpDown }
|
|
|
|
constructor TCustomUpDown.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
ControlStyle := ControlStyle - [csDoubleClicks];
|
|
FThousands := True;
|
|
FButtonDown := -1;
|
|
FPosition := 0;
|
|
FMin := 0;
|
|
FMax := 100;
|
|
FIncrement := 1;
|
|
|
|
FAlignButton := udRight;
|
|
FOrientation := udVertical;
|
|
Width := GetSystemMetrics(SM_CXVSCROLL);
|
|
Height := GetSystemMetrics(SM_CYVSCROLL) - 2; // is SM_CYVSCROLL wrong or is it just Qt
|
|
Height := Height + (Height div 2);
|
|
|
|
FRepeatTimer := TTimer.Create(Self);
|
|
FRepeatTimer.Interval := 125;
|
|
FRepeatTimer.OnTimer := RepeatTimer;
|
|
InputKeys := InputKeys + [ikArrows];
|
|
FArrowKeys := False;
|
|
end;
|
|
|
|
destructor TCustomUpDown.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TCustomUpDown.CanChange: Boolean;
|
|
var
|
|
Direction: TUpDownDirection;
|
|
begin
|
|
Result := True;
|
|
Direction := updNone;
|
|
|
|
if (FNewValue < Min) and (FNewValueDelta < 0) or
|
|
(FNewValue > Max) and (FNewValueDelta > 0) then
|
|
Direction := updNone
|
|
else if FNewValueDelta < 0 then
|
|
Direction := updDown
|
|
else if FNewValueDelta > 0 then
|
|
Direction := updUp;
|
|
|
|
if Assigned(FOnChanging) then
|
|
FOnChanging(Self, Result);
|
|
if Assigned(FOnChangingEx) then
|
|
FOnChangingEx(Self, Result, FNewValue, Direction);
|
|
end;
|
|
|
|
procedure TCustomUpDown.Click(Button: TUDBtnType);
|
|
begin
|
|
if Assigned(FOnClick) then
|
|
FOnClick(Self, Button);
|
|
end;
|
|
|
|
function TCustomUpDown.DoCanChange(NewVal, Delta: SmallInt): Boolean;
|
|
begin
|
|
FNewValue := NewVal;
|
|
FNewValueDelta := Delta;
|
|
Result := CanChange;
|
|
end;
|
|
|
|
function TCustomUpDown.GetPosition: SmallInt;
|
|
var
|
|
ErrCode: Integer;
|
|
begin
|
|
if Associate is TCustomEdit then
|
|
begin
|
|
if Thousands then
|
|
Val(ExcludeThousands(TCustomEdit(Associate).Text), Result, ErrCode)
|
|
else
|
|
Val(TCustomEdit(Associate).Text, Result, ErrCode);
|
|
if ErrCode = 0 then
|
|
FPosition := Result;
|
|
end;
|
|
Result := FPosition;
|
|
end;
|
|
|
|
procedure TCustomUpDown.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
if (Operation = opRemove) and (AComponent = Associate) then
|
|
Associate := nil;
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetAlignButton(Value: TUDAlignButton);
|
|
begin
|
|
if Value <> FAlignButton then
|
|
begin
|
|
FAlignButton := Value;
|
|
UpdateAlignment;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetArrowKeys(Value: Boolean);
|
|
begin
|
|
if Value <> FArrowKeys then
|
|
begin
|
|
if Value then
|
|
InputKeys := InputKeys + [ikArrows]
|
|
else
|
|
InputKeys := InputKeys - [ikArrows];
|
|
FArrowKeys := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetAssociate(Value: TWinControl);
|
|
begin
|
|
if Value <> FAssociate then
|
|
begin
|
|
if FAssociate <> nil then
|
|
FAssociate.RemoveFreeNotification(Self);
|
|
FAssociate := Value;
|
|
if FAssociate <> nil then
|
|
begin
|
|
FAssociate.FreeNotification(Self);
|
|
UpdateAlignment;
|
|
UpdatePosition(Position);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetMax(Value: SmallInt);
|
|
begin
|
|
if Value <> FMax then
|
|
begin
|
|
FMax := Value;
|
|
UpdatePosition(Position);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetMin(Value: SmallInt);
|
|
begin
|
|
if Value <> FMin then
|
|
begin
|
|
FMin := Value;
|
|
UpdatePosition(Position);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetOrientation(Value: TUDOrientation);
|
|
begin
|
|
if Value <> FOrientation then
|
|
begin
|
|
FOrientation := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetPosition(Value: SmallInt);
|
|
begin
|
|
if Value <> FPosition then
|
|
begin
|
|
if (Max > Min) and (Value > Max) and Wrap then
|
|
Value := Min;
|
|
if (Max > Min) and (Value < Min) and Wrap then
|
|
Value := Max;
|
|
UpdatePosition(Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.UpdatePosition(Value: SmallInt);
|
|
begin
|
|
if Value < Min then
|
|
Value := Min;
|
|
if (Max > Min) and (Value > Max) then
|
|
Value := Max;
|
|
|
|
if DoCanChange(Value, Value - FPosition) then
|
|
begin
|
|
FPosition := Value;
|
|
|
|
if Associate is TCustomEdit then
|
|
begin
|
|
if Thousands then
|
|
TCustomEdit(Associate).Text := IncludeThousands(IntToStr(FPosition))
|
|
else
|
|
TCustomEdit(Associate).Text := IntToStr(FPosition);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetThousands(Value: Boolean);
|
|
var
|
|
Pos: Integer;
|
|
begin
|
|
if Value <> FThousands then
|
|
begin
|
|
Pos := Position;
|
|
FThousands := Value;
|
|
UpdatePosition(Pos);
|
|
end;
|
|
end;
|
|
|
|
function TCustomUpDown.ButtonRect(ButtonIndex: Integer): TRect;
|
|
begin
|
|
Result := Rect(0, 0, 0, 0);
|
|
if Orientation = udVertical then
|
|
begin
|
|
case ButtonIndex of
|
|
0: Result := Rect(0, 0, Width, Height div 2);
|
|
1: Result := Rect(0, Height div 2, Width, Height);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
case ButtonIndex of
|
|
0: Result := Rect(0, 0, Width div 2, Height);
|
|
1: Result := Rect(Width div 2, 0, Width, Height);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.Paint;
|
|
const
|
|
BtnType: array[0..1, TUDOrientation] of Integer = (
|
|
(DFCS_SCROLLLEFT, DFCS_SCROLLUP),
|
|
(DFCS_SCROLLRIGHT, DFCS_SCROLLDOWN)
|
|
);
|
|
var
|
|
Flags, BtnFlags: Integer;
|
|
R: TRect;
|
|
Pixmap: QPixmapH;
|
|
Painter: QPainterH;
|
|
i: Integer;
|
|
begin
|
|
Pixmap := QPixmap_create(Width, Height, -1, QPixmapOptimization_DefaultOptim);
|
|
Painter := QPainter_create(Pixmap);
|
|
try
|
|
Flags := 0;
|
|
if not Enabled then
|
|
Flags := DFCS_INACTIVE;
|
|
|
|
for i := 0 to 1 do
|
|
begin
|
|
R := ButtonRect(i);
|
|
BtnFlags := 0;
|
|
if (FButtonDown = i) and FMouseOverButton then
|
|
BtnFlags := BtnFlags or DFCS_PUSHED;
|
|
DrawFrameControl(Painter, R, DFC_SCROLL, BtnType[i, Orientation] or Flags or BtnFlags);
|
|
end;
|
|
finally
|
|
QPainter_destroy(Painter);
|
|
Canvas.Start;
|
|
QPainter_drawPixmap(Canvas.Handle, 0, 0, Pixmap, 0, 0, Width, Height);
|
|
Canvas.Stop;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Button = mbLeft then
|
|
begin
|
|
for i := 0 to 1 do
|
|
if PtInRect(ButtonRect(i), Point(X, Y)) then
|
|
begin
|
|
MouseCapture := True;
|
|
FMouseOverButton := True;
|
|
FButtonDown := i;
|
|
ChangePosition(FButtonDown);
|
|
|
|
FRepeatTimer.Tag := 1;
|
|
FRepeatTimer.Enabled := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TCustomUpDown.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
begin
|
|
if (Button = mbLeft) and (FButtonDown <> -1) then
|
|
begin
|
|
FRepeatTimer.Enabled := False;
|
|
FButtonDown := -1;
|
|
MouseCapture := False;
|
|
Paint;
|
|
end;
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TCustomUpDown.RepeatTimer(Sender: TObject);
|
|
begin
|
|
if FRepeatTimer.Tag = 1 then
|
|
begin
|
|
FRepeatTimer.Tag := 0;
|
|
Exit;
|
|
end;
|
|
if (FButtonDown <> -1) then
|
|
begin
|
|
FMouseOverButton := PtInRect(ButtonRect(FButtonDown), ScreenToClient(Mouse.CursorPos));
|
|
if FMouseOverButton then
|
|
ChangePosition(FButtonDown)
|
|
else
|
|
Paint;
|
|
end;
|
|
end;
|
|
|
|
function TCustomUpDown.GetRepeatInterval: Integer;
|
|
begin
|
|
Result := FRepeatTimer.Interval;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetRepeatInterval(Value: Integer);
|
|
begin
|
|
if Value < 10 then
|
|
Value := 10;
|
|
FRepeatTimer.Interval := Value;
|
|
end;
|
|
|
|
function TCustomUpDown.AssociateHook(Sender: QObjectH;
|
|
Event: QEventH): Boolean;
|
|
begin
|
|
Result := False;
|
|
if (Associate <> nil) and (Associate.HandleAllocated) then
|
|
begin
|
|
if Sender = Associate.Handle then
|
|
begin
|
|
case QEvent_type(Event) of
|
|
QEventType_KeyPress:
|
|
begin
|
|
if QKeyEvent_key(QKeyEventH(Event)) = Key_Up then
|
|
begin
|
|
FMouseOverButton := True;
|
|
FButtonDown := 0;
|
|
ChangePosition(FButtonDown);
|
|
FButtonDown := -1;
|
|
Result := True;
|
|
end
|
|
else
|
|
if QKeyEvent_key(QKeyEventH(Event)) = Key_Down then
|
|
begin
|
|
FMouseOverButton := True;
|
|
FButtonDown := 1;
|
|
ChangePosition(FButtonDown);
|
|
FButtonDown := -1;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
QEventType_KeyRelease:
|
|
begin
|
|
if not (QKeyEvent_isAutoRepeat(QKeyEventH(Event))) then
|
|
begin
|
|
if QKeyEvent_key(QKeyEventH(Event)) = Key_Up then
|
|
begin
|
|
FButtonDown := -1;
|
|
Paint;
|
|
Result := True;
|
|
end
|
|
else
|
|
if QKeyEvent_key(QKeyEventH(Event)) = Key_Down then
|
|
begin
|
|
FButtonDown := -1;
|
|
Paint;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.ChangePosition(ButtonIndex: Integer);
|
|
begin
|
|
if Orientation = udVertical then
|
|
begin
|
|
case ButtonIndex of
|
|
0:
|
|
begin
|
|
Position := Position + Increment;
|
|
Click(btNext);
|
|
end;
|
|
1:
|
|
begin
|
|
Position := Position - Increment;
|
|
Click(btPrev);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
case ButtonIndex of
|
|
0:
|
|
begin
|
|
Position := Position - Increment;
|
|
Click(btPrev);
|
|
end;
|
|
1:
|
|
begin
|
|
Position := Position + Increment;
|
|
Click(btNext);
|
|
end;
|
|
end;
|
|
end;
|
|
Paint;
|
|
end;
|
|
|
|
procedure TCustomUpDown.UpdateAlignment;
|
|
begin
|
|
if Associate = nil then
|
|
Exit;
|
|
|
|
if AlignButton = udRight then
|
|
begin
|
|
Top := Associate.Top;
|
|
Left := Associate.BoundsRect.Right + 1;
|
|
end
|
|
else // udLeft
|
|
begin
|
|
Top := Associate.Top;
|
|
Left := Associate.Left - 1 - Width;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomUpDown.BoundsChanged;
|
|
begin
|
|
inherited BoundsChanged;
|
|
if ForceAlign then
|
|
UpdateAlignment;
|
|
end;
|
|
|
|
procedure TCustomUpDown.SetForceAlign(const Value: Boolean);
|
|
begin
|
|
FForceAlign := Value;
|
|
if FForceAlign then
|
|
UpdateAlignment;
|
|
end;
|
|
|
|
end.
|