| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- {
- Double Commander Components
- -------------------------------------------------------------------------
- Extended ComboBox classes
- Copyright (C) 2012 Przemyslaw Nagay ([email protected])
- Copyright (C) 2015-2023 Alexander Koblov ([email protected])
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
- 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. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- }
- unit KASComboBox;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
- ColorBox, Buttons, LMessages, Types, KASButton;
- const
- DEF_COLOR_STYLE = [cbStandardColors, cbExtendedColors,
- cbSystemColors, cbPrettyNames];
- type
- { TComboBoxWithDelItems }
- {en
- Combo box that allows removing items with Shift+Delete.
- }
- TComboBoxWithDelItems = class(TComboBox)
- protected
- procedure KeyDown(var Key: Word; Shift: TShiftState); override;
- end;
- { TComboBoxAutoWidth }
- TComboBoxAutoWidth = class(TComboBox)
- protected
- procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: Integer;
- WithThemeSpace: Boolean); override;
- procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
- const AXProportion, AYProportion: Double); override;
- end;
- { TKASColorBox }
- TKASColorBox = class(TColorBox)
- protected
- procedure SetCustomColor(AColor: TColor);
- function PickCustomColor: Boolean; override;
- procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: Integer;
- WithThemeSpace: Boolean); override;
- procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
- const AXProportion, AYProportion: Double); override;
- public
- constructor Create(AOwner: TComponent); override;
- published
- property DefaultColorColor default clNone;
- property Style default DEF_COLOR_STYLE;
- end;
- { TKASColorBoxButton }
- TKASColorBoxButton = class(TCustomControl)
- private
- function GetSelected: TColor;
- function GetStyle: TColorBoxStyle;
- function GetOnChange: TNotifyEvent;
- function GetColorDialog: TColorDialog;
- procedure SetSelected(AValue: TColor);
- procedure SetStyle(AValue: TColorBoxStyle);
- procedure SetOnChange(AValue: TNotifyEvent);
- procedure SetColorDialog(AValue: TColorDialog);
- protected
- FButton: TKASButton;
- FColorBox: TKASColorBox;
- procedure DoAutoSize; override;
- procedure EnabledChanged; override;
- procedure ButtonClick(Sender: TObject);
- class function GetControlClassDefaultSize: TSize; override;
- procedure CMParentColorChanged(var Message: TLMessage); message CM_PARENTCOLORCHANGED;
- public
- constructor Create(AOwner: TComponent); override;
- procedure SetFocus; override;
- function Focused: Boolean; override;
- property Selected: TColor read GetSelected write SetSelected default clBlack;
- published
- property Align;
- property Anchors;
- property TabOrder;
- property Constraints;
- property BorderSpacing;
- property AutoSize default True;
- property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
- property ColorDialog: TColorDialog read GetColorDialog write SetColorDialog;
- property Style: TColorBoxStyle read GetStyle write SetStyle default DEF_COLOR_STYLE;
- end;
- procedure Register;
- implementation
- uses
- LCLType, LCLIntf;
- procedure Register;
- begin
- RegisterComponents('KASComponents',[TComboBoxWithDelItems, TComboBoxAutoWidth,
- TKASColorBox, TKASColorBoxButton]);
- end;
- procedure CalculateSize(ComboBox: TCustomComboBox;
- var PreferredWidth: Integer; PreferredHeight: Integer);
- var
- DC: HDC;
- R: TRect;
- I, M: Integer;
- Flags: Cardinal;
- OldFont: HGDIOBJ;
- MaxWidth: Integer;
- LabelText: String;
- Idx: Integer = -1;
- begin
- with ComboBox do
- begin
- MaxWidth:= Constraints.MinMaxWidth(10000);
- if Items.Count = 0 then
- LabelText:= Text
- else begin
- M := Canvas.TextWidth(Text);
- for I := 0 to Items.Count - 1 do
- begin
- Flags := Canvas.TextWidth(Items[I]);
- if Flags > M then
- begin
- M := Flags;
- Idx := I;
- end;
- end;
- if Idx < 0 then
- LabelText := Text
- else begin
- LabelText := Items[Idx];
- end;
- end;
- if LabelText = '' then begin
- PreferredWidth := 1;
- Exit;
- end;
- DC := GetDC(Parent.Handle);
- try
- LabelText:= LabelText + 'W';
- R := Rect(0, 0, MaxWidth, 10000);
- OldFont := SelectObject(DC, HGDIOBJ(Font.Reference.Handle));
- Flags := DT_CALCRECT or DT_EXPANDTABS;
- DrawText(DC, PChar(LabelText), Length(LabelText), R, Flags);
- SelectObject(DC, OldFont);
- PreferredWidth := (R.Right - R.Left) + PreferredHeight;
- finally
- ReleaseDC(Parent.Handle, DC);
- end;
- end;
- end;
- function CalculateHeight(ComboBox: TCustomComboBox): Integer;
- var
- DC: HDC;
- R: TRect;
- Flags: Cardinal;
- OldFont: HGDIOBJ;
- LabelText: String;
- MaxHeight: Integer;
- begin
- with ComboBox do
- begin
- MaxHeight:= Constraints.MinMaxHeight(10000);
- DC := GetDC(Parent.Handle);
- try
- LabelText:= Items.Text;
- R := Rect(0, 0, 10000, MaxHeight);
- OldFont := SelectObject(DC, HGDIOBJ(Font.Reference.Handle));
- Flags := DT_CALCRECT or DT_EXPANDTABS or DT_SINGLELINE;
- DrawText(DC, PChar(LabelText), Length(LabelText), R, Flags);
- SelectObject(DC, OldFont);
- Result := (R.Bottom - R.Top);
- finally
- ReleaseDC(Parent.Handle, DC);
- end;
- end;
- end;
- { TComboBoxWithDelItems }
- procedure TComboBoxWithDelItems.KeyDown(var Key: Word; Shift: TShiftState);
- var
- Index: Integer;
- begin
- if DroppedDown and (Key = VK_DELETE) and (Shift = [ssShift]) then
- begin
- Index := ItemIndex;
- if (Index >= 0) and (Index < Items.Count) then
- begin
- Items.Delete(Index);
- ItemIndex := Index;
- Key := 0;
- end;
- end;
- inherited KeyDown(Key, Shift);
- end;
- { TComboBoxAutoWidth }
- procedure TComboBoxAutoWidth.CalculatePreferredSize(var PreferredWidth,
- PreferredHeight: Integer; WithThemeSpace: Boolean);
- begin
- inherited CalculatePreferredSize(PreferredWidth, PreferredHeight, WithThemeSpace);
- if csDesigning in ComponentState then Exit;
- if (Parent = nil) or (not Parent.HandleAllocated) then Exit;
- CalculateSize(Self, PreferredWidth, PreferredHeight);
- end;
- procedure TComboBoxAutoWidth.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
- const AXProportion, AYProportion: Double);
- begin
- // Don't auto adjust horizontal layout
- inherited DoAutoAdjustLayout(AMode, 1.0, AYProportion);
- end;
- { TKASColorBox }
- procedure TKASColorBox.SetCustomColor(AColor: TColor);
- var
- Index: Integer;
- begin
- for Index:= Ord(cbCustomColor in Style) to Items.Count - 1 do
- begin
- if Colors[Index] = AColor then
- begin
- Selected:= AColor;
- Exit;
- end;
- end;
- if cbCustomColor in Style then
- begin
- Items.Objects[0]:= TObject(PtrInt(AColor));
- end;
- Items.AddObject('$' + HexStr(AColor, 8), TObject(PtrInt(AColor)));
- Selected:= AColor;
- end;
- function TKASColorBox.PickCustomColor: Boolean;
- begin
- Result:= inherited PickCustomColor;
- SetCustomColor(Colors[0]);
- end;
- procedure TKASColorBox.CalculatePreferredSize(var PreferredWidth,
- PreferredHeight: Integer; WithThemeSpace: Boolean);
- begin
- inherited CalculatePreferredSize(PreferredWidth, PreferredHeight, WithThemeSpace);
- if csDesigning in ComponentState then Exit;
- if (Parent = nil) or (not Parent.HandleAllocated) then Exit;
- if (csSubComponent in ComponentStyle) then
- begin
- ItemHeight:= CalculateHeight(Self);
- if (Parent.Anchors * [akLeft, akRight] = [akLeft, akRight]) then
- Exit;
- end;
- CalculateSize(Self, PreferredWidth, PreferredHeight);
- PreferredWidth+= ColorRectWidth + ColorRectOffset;
- end;
- procedure TKASColorBox.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
- const AXProportion, AYProportion: Double);
- begin
- if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then
- begin
- if ColorRectWidthStored then
- ColorRectWidth:= Round(ColorRectWidth * AXProportion);
- end;
- // Don't auto adjust horizontal layout
- inherited DoAutoAdjustLayout(AMode, 1.0, AYProportion);
- end;
- constructor TKASColorBox.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- Style:= DEF_COLOR_STYLE;
- DefaultColorColor:= clNone;
- end;
- { TKASColorBoxButton }
- function TKASColorBoxButton.GetSelected: TColor;
- begin
- Result:= FColorBox.Selected;
- end;
- function TKASColorBoxButton.GetStyle: TColorBoxStyle;
- begin
- Result:= FColorBox.Style;
- end;
- function TKASColorBoxButton.GetOnChange: TNotifyEvent;
- begin
- Result:= FColorBox.OnChange;
- end;
- function TKASColorBoxButton.GetColorDialog: TColorDialog;
- begin
- Result:= FColorBox.ColorDialog;
- end;
- procedure TKASColorBoxButton.SetSelected(AValue: TColor);
- begin
- FColorBox.SetCustomColor(AValue);
- end;
- procedure TKASColorBoxButton.SetStyle(AValue: TColorBoxStyle);
- begin
- FColorBox.Style:= AValue;
- end;
- procedure TKASColorBoxButton.SetOnChange(AValue: TNotifyEvent);
- begin
- FColorBox.OnChange:= AValue;
- end;
- procedure TKASColorBoxButton.SetColorDialog(AValue: TColorDialog);
- begin
- FColorBox.ColorDialog:= AValue;
- end;
- procedure TKASColorBoxButton.DoAutoSize;
- begin
- inherited DoAutoSize;
- FButton.Constraints.MinWidth:= FButton.Height;
- end;
- procedure TKASColorBoxButton.EnabledChanged;
- begin
- if Enabled then
- FColorBox.Font.Color:= clDefault
- else begin
- FColorBox.Font.Color:= clGrayText;
- end;
- inherited EnabledChanged;
- end;
- procedure TKASColorBoxButton.ButtonClick(Sender: TObject);
- Var
- FreeDialog: Boolean;
- begin
- if csDesigning in ComponentState then Exit;
- with FColorBox do
- begin
- FreeDialog:= (ColorDialog = nil);
- if FreeDialog then
- begin
- ColorDialog:= TColorDialog.Create(GetTopParent);
- end;
- try
- with ColorDialog do
- begin
- Color:= FColorBox.Selected;
- if Execute Then
- begin
- FColorBox.SetCustomColor(Color);
- Invalidate;
- end;
- end;
- finally
- if FreeDialog Then
- begin
- ColorDialog.Free;
- ColorDialog:= nil;
- end;
- end;
- end;
- end;
- class function TKASColorBoxButton.GetControlClassDefaultSize: TSize;
- begin
- Result:= TKASColorBox.GetControlClassDefaultSize;
- Result.cx += Result.cy;
- end;
- procedure TKASColorBoxButton.CMParentColorChanged(var Message: TLMessage);
- begin
- if inherited ParentColor then
- begin
- inherited SetColor(Parent.Color);
- inherited ParentColor:= True;
- end;
- end;
- constructor TKASColorBoxButton.Create(AOwner: TComponent);
- begin
- FButton:= TKASButton.Create(Self);
- FColorBox:= TKASColorBox.Create(Self);
- inherited Create(AOwner);
- ControlStyle:= ControlStyle + [csNoFocus];
- BorderStyle:= bsNone;
- TabStop:= True;
- inherited TabStop:= False;
- with FColorBox do
- begin
- SetSubComponent(True);
- Align:= alClient;
- ParentColor:= False;
- ParentFont:= True;
- Parent:= Self;
- end;
- with FButton do
- begin
- Align:= alRight;
- Caption:= '..';
- BorderSpacing.Left:= 2;
- OnClick:= @ButtonClick;
- Parent:= Self;
- end;
- AutoSize:= True;
- Color:= clWindow;
- inherited ParentColor:= True;
- end;
- procedure TKASColorBoxButton.SetFocus;
- begin
- FColorBox.SetFocus;
- end;
- function TKASColorBoxButton.Focused: Boolean;
- begin
- Result:= FColorBox.Focused;
- end;
- end.
|