New files for ComboBoxEx and CheckComboBox.

git-svn-id: trunk@46270 -
This commit is contained in:
juha 2014-09-21 10:03:38 +00:00
parent c65ace9cc9
commit e0c5aeb65b
5 changed files with 1264 additions and 0 deletions

4
.gitattributes vendored
View File

@ -5693,6 +5693,7 @@ images/components/tcalculatordialog.png -text svneol=unset#image/png
images/components/tcalendar.png -text svneol=unset#image/png
images/components/tcalendardialog.png -text svneol=unset#image/png
images/components/tcheckbox.png -text svneol=unset#image/png
images/components/tcheckcombobox.png -text svneol=unset#image/png
images/components/tcheckgroup.png -text svneol=unset#image/png
images/components/tchecklistbox.png -text svneol=unset#image/png
images/components/tcolorbox.png -text svneol=unset#image/png
@ -5700,6 +5701,7 @@ images/components/tcolorbutton.png -text svneol=unset#image/png
images/components/tcolordialog.png -text svneol=unset#image/png
images/components/tcolorlistbox.png -text svneol=unset#image/png
images/components/tcombobox.png -text svneol=unset#image/png
images/components/tcomboboxex.png -text svneol=unset#image/png
images/components/tcontrolbar.png -text svneol=unset#image/png
images/components/tcoolbar.png -text svneol=unset#image/png
images/components/tdatasource.png -text svneol=unset#image/png
@ -6154,6 +6156,7 @@ lcl/calendar.pp svneol=native#text/pascal
lcl/checklst.pas svneol=native#text/pascal
lcl/clipbrd.pp svneol=native#text/pascal
lcl/colorbox.pas svneol=native#text/pascal
lcl/comboex.pas svneol=native#text/pascal
lcl/comctrls.pp svneol=native#text/pascal
lcl/controls.pp svneol=native#text/pascal
lcl/cursors.res -text
@ -6293,6 +6296,7 @@ lcl/include/canvas.inc svneol=native#text/pascal
lcl/include/checkbox.inc svneol=native#text/pascal
lcl/include/clipbrd.inc svneol=native#text/pascal
lcl/include/colorbutton.inc svneol=native#text/pascal
lcl/include/comboex.inc svneol=native#text/plain
lcl/include/commondialog.inc svneol=native#text/pascal
lcl/include/containedaction.inc svneol=native#text/pascal
lcl/include/control.inc svneol=native#text/pascal

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

395
lcl/comboex.pas Normal file
View File

@ -0,0 +1,395 @@
{ Visual components TComboBoxEx and TCheckComboBox
Copyright (C) 2014 Vojtěch Čihák, e-mail: cihakvjtch@seznam.cz
This library is free software; you can redistribute it and/or modify it under the terms of the
GNU Library General Public License as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version with the following modification:
As a special exception, the copyright holders of this library give you permission to link this
library with independent modules to produce an executable, regardless of the license terms of
these independent modules,and to copy and distribute the resulting executable under terms of
your choice, provided that you also meet, for each linked independent module, the terms and
conditions of the license of that module. An independent module is a module which is not derived
from or based on this library. If you modify this library, you may extend this exception to your
version of the library, but you are not obligated to do so. If you do not wish to do so, delete
this exception statement from your 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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License along with this
library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
}
unit ComboEx;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, ImgList, Controls, StdCtrls, ComCtrls, ExtCtrls, Graphics,
GraphUtil, LCLIntf, LCLType, LMessages, LResources, Themes, types;
type
{$PACKENUM 2}
TAutoCompleteOption = (acoAutoSuggest, acoAutoAppend, acoSearch, acoFilterPrefixes,
acoUseTab, acoUpDownKeyDropsList, acoRtlReading);
TAutoCompleteOptions = set of TAutoCompleteOption;
TComboBoxExStyle = (csExDropDown, csExSimple, csExDropDownList);
TComboBoxExStyleEx = (csExCaseSensitive, csExNoEditImage, csExNoEditImageIndent,
csExNoSizeLimit, csExPathWordBreak);
TComboBoxExStyles = set of TComboBoxExStyleEx;
TCustomData = Pointer;
TListControlItems = class; { forward }
TListItemsCompare = function (AList: TListControlItems; AItem1, AItem2: Integer): Integer;
TListItemsSortType = TSortType;
{ Events }
TCheckItemChange = procedure(Sender: TObject; AIndex: Integer) of object;
TListControlItem = class; { forward }
TListCompareEvent = function(AList: TListControlItems; AItem1, AItem2: TListControlItem): Integer of object;
{ TListControlItem }
TListControlItem = class(TCollectionItem)
private
FCaption: TTranslateString;
FData: TCustomData;
FImageIndex: SmallInt;
procedure SetCaption(const AValue: TTranslateString);
procedure SetImageIndex(AValue: SmallInt);
public
property Data: TCustomData read FData write FData;
constructor Create(ACollection: TCollection); override;
published
property Caption: TTranslateString read FCaption write SetCaption;
property ImageIndex: SmallInt read FImageIndex write SetImageIndex default -1;
end;
{ TComboExItem }
TComboExItem = class(TListControlItem)
private
FIndent: SmallInt;
FOverlayImageIndex: SmallInt;
FSelectedImageIndex: SmallInt;
procedure SetIndent(AValue: SmallInt);
procedure SetOverlayImageIndex(AValue: SmallInt);
procedure SetSelectedImageIndex(AValue: SmallInt);
protected const
cDefCaption = 'ItemEx';
public
constructor Create(ACollection: TCollection); override;
destructor Destroy; override;
published
property Indent: SmallInt read FIndent write SetIndent default -1;
property OverlayImageIndex: SmallInt read FOverlayImageIndex write SetOverlayImageIndex default -1;
property SelectedImageIndex: SmallInt read FSelectedImageIndex write SetSelectedImageIndex default -1;
end;
{ TListControlItems }
TListControlItems = class(TOwnedCollection)
private
FCaseSensitive: Boolean;
FSortType: TListItemsSortType;
FOnCompare: TListCompareEvent;
FCompare: TListItemsCompare;
function GetItems(AIndex: Integer): TListControlItem;
procedure SetCaseSensitive(AValue: Boolean);
procedure SetSortType(AValue: TListItemsSortType);
protected
function CompareItems(AItem1, AItem2: TListControlItem): Integer; virtual;
function DoCustomSort(AItem1, AItem2: TListControlItem): Integer;
function DoOnCompare(AItem1, AItem2: TListControlItem): Integer;
procedure Update(AItem: TCollectionItem); override;
public
function Add: TListControlItem;
procedure CustomSort(ACompare: TListItemsCompare);
procedure Sort;
property Items[AIndex: Integer]: TListControlItem read GetItems; default;
published
property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive default False;
property SortType: TListItemsSortType read FSortType write SetSortType default stNone;
property OnCompare: TListCompareEvent read FOnCompare write FOnCompare;
end;
{ TComboExItems }
TComboExItems = class(TListControlItems)
private
function GetComboItems(AIndex: Integer): TComboExItem;
protected
FAddingOrDeletingItem: Boolean;
procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); override;
procedure Update(Item: TCollectionItem); override;
public
function Add: TComboExItem; overload;
function Add(const ACaption: string; AImageIndex: SmallInt = -1;
AOverlayImageIndex: SmallInt = -1; ASelectedImageIndex: SmallInt = -1;
AIndent: SmallInt = -1; AData: TCustomData = nil): TComboExItem; overload;
function Insert(AIndex: Integer): TComboExItem;
property ComboItems[AIndex: Integer]: TComboExItem read GetComboItems; default;
end;
{ TCustomComboBoxEx }
TCustomComboBoxEx = class(TCustomComboBox)
private
FAutoCompleteOptions: TAutoCompleteOptions;
FImages: TCustomImageList;
FItemsEx: TComboExItems;
FStyle: TComboBoxExStyle;
FStyleEx: TComboBoxExStyles;
procedure SetImages(AValue: TCustomImageList);
procedure SetStyle(AValue: TComboBoxExStyle); reintroduce;
procedure SetStyleEx(AValue: TComboBoxExStyles);
protected const
cDefAutoCompOpts = [acoAutoAppend];
cDefStyle = csExDropDown;
protected
FNeedMeasure: Boolean;
FRightToLeft: Boolean;
FTextHeight: SmallInt;
procedure CMBiDiModeChanged(var Message: TLMessage); message CM_BIDIMODECHANGED;
procedure DrawItem(Index: Integer; ARect: TRect; State: TOwnerDrawState); override;
procedure FontChanged(Sender: TObject); override;
procedure InitializeWnd; override;
procedure SetItemHeight(const AValue: Integer); override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function Add: Integer; overload;
procedure Add(const ACaption: string; AIndent: SmallInt = -1;
AImgIdx: SmallInt = -1; AOverlayImgIdx: SmallInt = -1;
ASelectedImgIdx: SmallInt = -1); overload;
procedure AddItem(const Item: String; AnObject: TObject); override;
procedure AssignItemsEx(AItems: TStrings); overload;
procedure AssignItemsEx(AItemsEx: TComboExItems); overload;
procedure Clear; override;
procedure Delete(AIndex: Integer);
procedure DeleteSelected;
procedure Insert(AIndex: Integer; const ACaption: string; AIndent: SmallInt = -1;
AImgIdx: SmallInt = -1; AOverlayImgIdx: SmallInt = -1;
ASelectedImgIdx: SmallInt = -1);
property AutoCompleteOptions: TAutoCompleteOptions read FAutoCompleteOptions
write FAutoCompleteOptions default cDefAutoCompOpts;
property Images: TCustomImageList read FImages write SetImages;
property ItemsEx: TComboExItems read FItemsEx write FItemsEx;
property Style: TComboBoxExStyle read FStyle write SetStyle default cDefStyle;
property StyleEx: TComboBoxExStyles read FStyleEx write SetStyleEx default [];
end;
{ TComboBoxEx }
TComboBoxEx = class(TCustomComboBoxEx)
published
property Align;
property Anchors;
property ArrowKeysTraverseList;
property AutoComplete;
property AutoCompleteOptions;
property AutoCompleteText;
property AutoDropDown;
property AutoSelect;
property AutoSize;
property BidiMode;
property BorderSpacing;
property BorderStyle;
property CharCase;
property Color;
property Constraints;
property DragCursor;
property DragKind;
property DragMode;
property DropDownCount;
property Enabled;
property Font;
property Images;
property ItemHeight;
property ItemsEx; { do not change order; ItemsEx must be before ItemIndex }
property ItemIndex;
property ItemWidth;
property MaxLength;
property OnChange;
property OnChangeBounds;
property OnClick;
property OnCloseUp;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDropDown;
property OnEditingDone;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnGetItems;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnSelect;
property OnStartDock;
property OnStartDrag;
property OnUTF8KeyPress;
property ParentBidiMode;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property ShowHint;
property Style;
property StyleEx;
property TabOrder;
property TabStop;
property Text;
property Visible;
end;
{ TCheckComboItemState }
TCheckComboItemState = record
State: TCheckBoxState;
Enabled: Boolean;
Data: TObject;
end;
PTCheckComboItemState = ^TCheckComboItemState;
{ TCustomCheckCombo }
TCustomCheckCombo = class(TCustomComboBox)
private
FAllowGrayed: Boolean;
FOnItemChange: TCheckItemChange;
function GetChecked(AIndex: Integer): Boolean;
function GetCount: Integer;
function GetItemEnabled(AIndex: Integer): Boolean;
function GetObject(AIndex: Integer): TObject;
function GetState(AIndex: Integer): TCheckBoxState;
procedure SetChecked(AIndex: Integer; AValue: Boolean);
procedure SetItemEnabled(AIndex: Integer; AValue: Boolean);
procedure SetObject(AIndex: Integer; AValue: TObject);
procedure SetState(AIndex: Integer; AValue: TCheckBoxState);
protected
FCheckHighlight: Boolean;
FCheckSize: TSize;
FHiLiteLeft: Integer;
FHiLiteRight: Integer;
FNeedMeasure: Boolean;
FRejectDropDown: Boolean;
FRejectToggleOnSelect: Boolean;
FRightToLeft: Boolean;
FTextHeight: SmallInt;
procedure CMBiDiModeChanged(var Message: TLMessage); message CM_BIDIMODECHANGED;
procedure ClearItemStates;
procedure CloseUp; override;
procedure DrawItem(Index: Integer; ARect: TRect; State: TOwnerDrawState); override;
procedure DropDown; override;
procedure FontChanged(Sender: TObject); override;
procedure InitializeWnd; override;
procedure InitItemStates;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Loaded; override;
procedure MouseLeave; override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure SetItemHeight(const AValue: Integer); override;
procedure Select; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AddItem(const AItem: string; AState: TCheckBoxState; AEnabled: Boolean = True); reintroduce;
procedure AssignItems(AItems: TStrings);
procedure Clear; override;
procedure DeleteItem(AIndex: Integer);
procedure CheckAll(AState: TCheckBoxState; AAllowGrayed: Boolean = True; AAllowDisabled: Boolean = True);
procedure Toggle(AIndex: Integer);
property AllowGrayed: Boolean read FAllowGrayed write FAllowGrayed default False;
property Count: Integer read GetCount;
property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked;
property ItemEnabled[AIndex: Integer]: Boolean read GetItemEnabled write SetItemEnabled;
property Objects[AIndex: Integer]: TObject read GetObject write SetObject;
property State[AIndex: Integer]: TCheckBoxState read GetState write SetState;
property OnItemChange: TCheckItemChange read FOnItemChange write FOnItemChange;
end;
{ TCheckComboBox }
TCheckComboBox = class(TCustomCheckCombo)
published
property Align;
property AllowGrayed;
property Anchors;
property ArrowKeysTraverseList;
property AutoDropDown;
property AutoSize;
property BidiMode;
property BorderSpacing;
property BorderStyle;
property Color;
property Constraints;
property Count;
property DragCursor;
property DragKind;
property DragMode;
property DropDownCount;
property Enabled;
property Font;
property ItemHeight;
property ItemIndex;
property Items;
property ItemWidth;
property MaxLength;
property OnChange;
property OnChangeBounds;
property OnClick;
property OnCloseUp;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnDropDown;
property OnEditingDone;
property OnEnter;
property OnExit;
property OnGetItems;
property OnItemChange;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
property OnSelect;
property OnUTF8KeyPress;
property ParentBidiMode;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Sorted;
property TabOrder;
property TabStop;
property Text;
property Visible;
end;
procedure Register;
implementation
{$include comboex.inc}
procedure Register;
begin
{$I comboex.lrs}
RegisterComponents('Misc', [TComboBoxEx, TCheckComboBox]);
end;
end.

865
lcl/include/comboex.inc Normal file
View File

@ -0,0 +1,865 @@
{%MainUnit comboex.pas}
{*****************************************************************************
TCustomComboBoxEx, TCustomCheckComboBox
*****************************************************************************
*****************************************************************************
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
}
{ TListControlItem }
constructor TListControlItem.Create(ACollection: TCollection);
begin
inherited Create(ACollection);
FImageIndex:=-1;
end;
{ TListControlItem.Setters }
procedure TListControlItem.SetCaption(const AValue: TTranslateString);
begin
if FCaption=AValue then exit;
FCaption:=AValue;
Changed(False);
end;
procedure TListControlItem.SetImageIndex(AValue: SmallInt);
begin
if FImageIndex=AValue then exit;
FImageIndex:=AValue;
Changed(False);
end;
{ TComboExItem }
constructor TComboExItem.Create(ACollection: TCollection);
begin
inherited Create(ACollection);
FIndent:=-1;
FOverlayImageIndex:=-1;
FSelectedImageIndex:=-1;
end;
destructor TComboExItem.Destroy;
begin
{ normally, Items.Count should be already MenuItems.Count-1 ATM }
{ this solves case when item is not deleted via Collection.Delete(Index) }
{ but directly via Item.Free (exactly what Collection Editor of IDE does) }
{ therefore Notify must be called from here, so count of Items and MenuItems remains same }
if assigned(Collection) and assigned(Collection.Owner) and
not (csDestroying in (Collection.Owner as TCustomComboBoxEx).ComponentState)
and (Collection.Count <= (Collection.Owner as TCustomComboBoxEx).Items.Count)
then TComboExItems(Collection).Notify(self, cnDeleting);
inherited Destroy;
end;
{ TComboExItem.Setters }
procedure TComboExItem.SetIndent(AValue: SmallInt);
begin
if FIndent=AValue then exit;
FIndent:=AValue;
Changed(False);
end;
procedure TComboExItem.SetOverlayImageIndex(AValue: SmallInt);
begin
if FOverlayImageIndex=AValue then exit;
FOverlayImageIndex:=AValue;
{ Changed(False); }
end;
procedure TComboExItem.SetSelectedImageIndex(AValue: SmallInt);
begin
if FSelectedImageIndex=AValue then exit;
FSelectedImageIndex:=AValue;
Changed(False);
end;
{ TListControlItems }
function TListControlItems.Add: TListControlItem;
begin
Result:=TListControlItem.Create(self);
end;
function TListControlItems.CompareItems(AItem1, AItem2: TListControlItem): Integer;
begin
if CaseSensitive
then Result:=CompareStr((AItem1 as TListControlItem).Caption,
(AItem2 as TListControlItem).Caption)
else Result:=CompareStr(lowercase((AItem1 as TListControlItem).Caption),
lowercase((AItem2 as TListControlItem).Caption));
end;
procedure TListControlItems.CustomSort(ACompare: TListItemsCompare);
begin
if assigned(ACompare) then
begin
FCompare:=ACompare;
Sort;
FCompare:=nil;
end;
end;
function TListControlItems.DoCustomSort(AItem1, AItem2: TListControlItem): Integer;
begin
Result:=FCompare(self, AItem1.Index, AItem2.Index);
end;
function TListControlItems.DoOnCompare(AItem1, AItem2: TListControlItem): Integer;
begin
Result:=OnCompare(self, AItem1, AItem2);
end;
procedure TListControlItems.Sort;
var pCompareItems: function(AItem1, AItem2: TListControlItem): Integer of object;
procedure QuickSort(aTop, aBottom: Integer);
var i, j, aPivot: Integer;
begin
repeat
i:=aTop;
j:=aBottom;
aPivot:=(aTop+aBottom) div 2;
repeat
while pCompareItems(Items[aPivot], Items[i])>0 do
inc(i);
while pCompareItems(Items[aPivot], Items[j])<0 do
dec(j);
if i<=j then
begin
if i<>j then
if pCompareItems(Items[i], Items[j])<>0 then Exchange(i, j);
if aPivot=i
then aPivot:=j
else if aPivot=j then aPivot:=i;
inc(i);
dec(j);
end;
until i>j;
if aTop<j then QuickSort(aTop, j);
aTop:=i;
until i>=aBottom;
end;
var aID: Integer;
begin
pCompareItems:=nil;
if assigned(FCompare)
then pCompareItems:=@DoCustomSort
else
case SortType of
stData: if assigned(OnCompare) then pCompareItems:=@DoOnCompare;
stText: pCompareItems:=@CompareItems;
stBoth: if assigned(OnCompare)
then pCompareItems:=@DoOnCompare
else pCompareItems:=@CompareItems;
end;
aID:=Items[(Owner as TCustomComboBoxEx).ItemIndex].ID;
BeginUpdate;
if assigned(pCompareItems) then QuickSort(0, Count-1);
(Owner as TCustomComboBoxEx).ItemIndex:=FindItemID(aID).Index;
EndUpdate;
end;
procedure TListControlItems.Update(AItem: TCollectionItem);
begin
inherited Update(AItem);
end;
{ TListControlItems.Getters and Setters }
function TListControlItems.GetItems(AIndex: Integer): TListControlItem;
begin
Result:=GetItem(AIndex) as TListControlItem;
end;
procedure TListControlItems.SetCaseSensitive(AValue: Boolean);
begin
if FCaseSensitive=AValue then exit;
FCaseSensitive:=AValue;
end;
procedure TListControlItems.SetSortType(AValue: TListItemsSortType);
begin
if FSortType=AValue then exit;
FSortType:=AValue;
Sort;
end;
{ TComboExItems }
function TComboExItems.Add: TComboExItem;
begin
Result:=TComboExItem.Create(self);
end;
function TComboExItems.Add(const ACaption: string; AImageIndex: SmallInt;
AOverlayImageIndex: SmallInt; ASelectedImageIndex: SmallInt; AIndent: SmallInt; AData: TCustomData
): TComboExItem;
begin
Result:=Add();
with Result do
begin
Caption:=ACaption;
Indent:=AIndent;
ImageIndex:=AImageIndex;
OverlayImageIndex:=AOverlayImageIndex;
SelectedImageIndex:=ASelectedImageIndex;
Data:=AData;
end;
end;
function TComboExItems.Insert(AIndex: Integer): TComboExItem;
begin
Result:=Insert(AIndex);
end;
procedure TComboExItems.Notify(Item: TCollectionItem; Action: TCollectionNotification);
var i: Integer;
begin
inherited Notify(Item, Action);
case Action of
cnAdded:
begin
FAddingOrDeletingItem:=True;
with Owner as TCustomComboBoxEx do
begin
Items.Add('');
if not (csLoading in ComponentState) then
TComboExItem(Item).FCaption:=TComboExItem.cDefCaption+inttostr(Item.ID);
end;
end;
cnDeleting:
begin
FAddingOrDeletingItem:=True;
with Owner as TCustomComboBoxEx do
begin
i:=ItemIndex;
Items.Delete(Item.Index);
if i<Count then ItemIndex:=i
else if i>0 then ItemIndex:=i-1;
end;
end;
end;
end;
procedure TComboExItems.Update(Item: TCollectionItem);
var aItemIndex: Integer;
begin
inherited Update(Item);
aItemIndex:=(Owner as TCustomComboBoxEx).ItemIndex;
if not assigned(Item) or ((aItemIndex>=0) and
(Item=(Owner as TCustomComboBoxEx).ItemsEx[aItemIndex]))
then (Owner as TCustomComboBoxEx).Invalidate;
FAddingOrDeletingItem:=False;
end;
{ TComboExItems.Getters and Setters }
function TComboExItems.GetComboItems(AIndex: Integer): TComboExItem;
begin
Result:=Items[AIndex] as TComboExItem;
end;
{ TCustomComboBoxEx }
constructor TCustomComboBoxEx.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FAutoCompleteOptions:=cDefAutoCompOpts;
FItemsEx:=TComboExItems.Create(self, TComboExItem);
FNeedMeasure:=True;
ReadOnly:=True;
inherited Style:=csOwnerDrawFixed;
FStyle:=cDefStyle;
FStyleEx:=[];
end;
destructor TCustomComboBoxEx.Destroy;
begin
FreeAndNil(FItemsEx);
inherited Destroy;
end;
procedure TCustomComboBoxEx.Add(const ACaption: string; AIndent: SmallInt; AImgIdx: SmallInt;
AOverlayImgIdx: SmallInt; ASelectedImgIdx: SmallInt);
begin
Insert(ItemsEx.Count, ACaption, AIndent, AImgIdx, AOverlayImgIdx, ASelectedImgIdx);
end;
function TCustomComboBoxEx.Add: Integer;
begin
Result:=ItemsEx.Count;
Insert(Result, TComboExItem.cDefCaption);
end;
procedure TCustomComboBoxEx.AddItem(const Item: String; AnObject: TObject);
begin
Insert(ItemsEx.Count, Item);
ItemsEx[ItemsEx.Count].Data:=AnObject;
end;
procedure TCustomComboBoxEx.AssignItemsEx(AItemsEx: TComboExItems);
begin
ItemsEx.Assign(AItemsEx);
end;
procedure TCustomComboBoxEx.AssignItemsEx(AItems: TStrings);
var i: Integer;
begin
FItemsEx.BeginUpdate;
FItemsEx.Clear;
for i:=0 to AItems.Count-1 do
ItemsEx.Add(AItems[i]);
FItemsEx.EndUpdate;
end;
procedure TCustomComboBoxEx.Clear;
begin
FItemsEx.Clear;
end;
procedure TCustomComboBoxEx.CMBiDiModeChanged(var Message: TLMessage);
begin
inherited CMBiDiModeChanged(Message);
FRightToLeft:=IsRightToLeft;
Invalidate;
end;
procedure TCustomComboBoxEx.Delete(AIndex: Integer);
begin
ItemsEx.Delete(AIndex);
end;
procedure TCustomComboBoxEx.DeleteSelected;
begin
if ItemIndex>=0 then Delete(ItemIndex);
end;
procedure TCustomComboBoxEx.DrawItem(Index: Integer; ARect: TRect; State: TOwnerDrawState);
const caThemes: array [Boolean] of TThemedButton = (tbPushButtonDisabled, tbPushButtonNormal);
cItemIndent: SmallInt = 2;
var aDetail: TThemedElementDetails;
aDropped: Boolean;
aEnabled: Boolean;
aFlags: Cardinal;
aFocusedEditableMainItemNoDD: Boolean; { combo has edit-like line edit in csDropDownList (Win) and is closed (not DroppedDown }
aImgPoint: TPoint;
aIndent: SmallInt;
aItemIndex: SmallInt;
aMainItem: Boolean;
anyRect: TRect;
begin { do not call inherited ! }
aDropped:=DroppedDown;
aEnabled:=IsEnabled;
aMainItem:= (ARect.Left>0);
{$IF DEFINED(LCLWin32) or DEFINED(LCLWin64)}
aFocusedEditableMainItemNoDD := (Focused and aMainItem and not aDropped);
{$ELSE}
aFocusedEditableMainItemNoDD := False;
{$ENDIF}
if aDropped and not aMainItem or aFocusedEditableMainItemNoDD then
begin
if not (odSelected in State) then Canvas.Brush.Color:=clWindow;
Canvas.Brush.Style:=bsSolid;
Canvas.FillRect(ARect);
end;
aDetail:=ThemeServices.GetElementDetails(caThemes[aEnabled]);
if FNeedMeasure then
begin
FTextHeight:=Canvas.TextHeight('ŠjÁÇ');
FNeedMeasure := False;
end;
if not aMainItem
then aIndent:=TComboExItem(ItemsEx[Index]).Indent
else aIndent:=-1;
if aIndent<0 then aIndent:=0;
inc(aIndent, cItemIndent);
if assigned(Images) then
begin
aItemIndex:=-1;
if (aMainItem or (odSelected in State)) and
((ItemsEx[Index].SelectedImageIndex>=0) and (ItemsEx[Index].SelectedImageIndex<Images.Count))
then aItemIndex:=ItemsEx[Index].SelectedImageIndex;
if aItemIndex<0 then aItemIndex:=ItemsEx[Index].ImageIndex;
if aItemIndex>=0 then
begin
if not FRightToLeft
then aImgPoint.X:=ARect.Left+aIndent
else aImgPoint.X:=ARect.Right-aIndent-Images.Width;
aImgPoint.Y:=(ARect.Bottom+ARect.Top-Images.Height) div 2;
ThemeServices.DrawIcon(Canvas, aDetail, aImgPoint, Images, aItemIndex);
end;
inc(aIndent, Images.Width+2*cItemIndent);
end;
Canvas.Brush.Style:=bsClear;
if (not (odSelected in State) or not aDropped) and not aFocusedEditableMainItemNoDD
then Canvas.Font.Color:=clWindowText
else Canvas.Font.Color:=clHighlightText;
if aFocusedEditableMainItemNoDD then
begin
LCLIntf.SetBkColor(Canvas.Handle, ColorToRGB(clBtnFace));
LCLIntf.DrawFocusRect(Canvas.Handle, aRect);
end;
aFlags:=DT_END_ELLIPSIS+DT_VCENTER+DT_SINGLELINE+DT_NOPREFIX;
if not FRightToLeft then
begin
anyRect.Left:=ARect.Left+aIndent;
anyRect.Right:=ARect.Right;
end else
begin
anyRect.Right:=ARect.Right-aIndent;
anyRect.Left:=ARect.Left;
aFlags:=aFlags or DT_RIGHT or DT_RTLREADING;
end;
anyRect.Top:=(ARect.Top+ARect.Bottom-FTextHeight) div 2;
anyRect.Bottom:=anyRect.Top+FTextHeight;
ThemeServices.DrawText(Canvas, aDetail, ItemsEx[Index].Caption, anyRect, aFlags, 0);
end;
procedure TCustomComboBoxEx.FontChanged(Sender: TObject);
begin
FNeedMeasure:=True;
inherited FontChanged(Sender);
end;
procedure TCustomComboBoxEx.InitializeWnd;
begin
inherited InitializeWnd;
FRightToLeft:=IsRightToLeft;
end;
procedure TCustomComboBoxEx.Insert(AIndex: Integer; const ACaption: string; AIndent: SmallInt = -1;
AImgIdx: SmallInt = -1; AOverlayImgIdx: SmallInt = -1; ASelectedImgIdx: SmallInt = -1);
var aItem: TCollectionItem;
begin
aItem:=ItemsEx.Insert(AIndex);
with aItem as TComboExItem do
begin
Caption:=ACaption;
Indent:=AIndent;
ImageIndex:=AImgIdx;
OverlayImageIndex:=AOverlayImgIdx;
SelectedImageIndex:=ASelectedImgIdx;
end;
end;
procedure TCustomComboBoxEx.SetItemHeight(const AValue: Integer);
begin
inherited SetItemHeight(AValue);
FNeedMeasure:=True;
end;
{ TCustomComboBoxEx.Setters }
procedure TCustomComboBoxEx.SetImages(AValue: TCustomImageList);
begin
if FImages=AValue then exit;
FImages:=AValue;
Invalidate;
end;
procedure TCustomComboBoxEx.SetStyle(AValue: TComboBoxExStyle);
begin
if FStyle=AValue then exit;
FStyle:=AValue;
end;
procedure TCustomComboBoxEx.SetStyleEx(AValue: TComboBoxExStyles);
begin
if FStyleEx=AValue then exit;
FStyleEx:=AValue;
end;
{ TCustomCheckCombo }
constructor TCustomCheckCombo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TStringList(Items).Duplicates:=dupIgnore;
ReadOnly:=True;
Style:=csOwnerDrawFixed;
FNeedMeasure:=True;
FRejectToggleOnSelect:=True;
end;
destructor TCustomCheckCombo.Destroy;
begin
ClearItemStates;
inherited Destroy;
end;
procedure TCustomCheckCombo.AddItem(const AItem: string; AState: TCheckBoxState; AEnabled: Boolean);
var pItemState: PTCheckComboItemState;
begin
pItemState:=new(PTCheckComboItemState);
pItemState^.State:=aState;
pItemState^.Enabled:=AEnabled;
pItemState^.Data:=nil;
inherited AddItem(AItem, TObject(pItemState));
end;
procedure TCustomCheckCombo.AssignItems(AItems: TStrings);
begin
ClearItemStates;
Items.Assign(AItems);
InitItemStates;
end;
procedure TCustomCheckCombo.CheckAll(AState: TCheckBoxState; AAllowGrayed: Boolean;
AAllowDisabled: Boolean);
var i: Integer;
begin
for i:=0 to Items.Count-1 do
begin
if (AAllowGrayed or (State[i]<>cbGrayed)) and (AAllowDisabled or ItemEnabled[i])
then State[i]:=AState;
end;
end;
procedure TCustomCheckCombo.Clear;
begin
ClearItemStates;
inherited Clear;
end;
procedure TCustomCheckCombo.ClearItemStates;
var i: Integer;
begin
for i:=0 to Items.Count-1 do
begin
dispose(PTCheckComboItemState(Items.Objects[i]));
Items.Objects[i]:=nil;
end;
end;
procedure TCustomCheckCombo.CloseUp;
begin
if FRejectDropDown then
begin
FRejectDropDown:=False;
Update;
end else
inherited CloseUp;
end;
procedure TCustomCheckCombo.CMBiDiModeChanged(var Message: TLMessage);
begin
inherited CMBiDiModeChanged(Message);
FRightToLeft:=IsRightToLeft;
FNeedMeasure:=True;
Invalidate;
end;
procedure TCustomCheckCombo.DeleteItem(AIndex: Integer);
begin
if (AIndex>=0) and (AIndex<Items.Count) then
begin
dispose(PTCheckComboItemState(Items.Objects[AIndex]));
Items.Delete(AIndex);
end;
end;
procedure TCustomCheckCombo.DrawItem(Index: Integer; ARect: TRect; State: TOwnerDrawState);
{ Enabled, State, Highlighted }
const caCheckThemes: array [Boolean, TCheckBoxState, Boolean] of TThemedButton =
{ normal, highlighted }
(((tbCheckBoxUncheckedDisabled, tbCheckBoxUncheckedDisabled), { disabled, unchecked }
(tbCheckBoxCheckedDisabled, tbCheckBoxCheckedDisabled), { disabled, checked }
(tbCheckBoxMixedDisabled, tbCheckBoxMixedDisabled)), { disabled, greyed }
((tbCheckBoxUncheckedNormal, tbCheckBoxUncheckedHot), { enabled, unchecked }
(tbCheckBoxCheckedNormal, tbCheckBoxCheckedHot), { enabled, checked }
(tbCheckBoxMixedNormal, tbCheckBoxMixedHot))); { enabled, greyed }
cCheckIndent: SmallInt = 2;
cTextIndent: SmallInt = 5;
var aDetail: TThemedElementDetails;
aDropped: Boolean;
aEnabled: Boolean;
aFlags: Cardinal;
aFocusedEditableMainItemNoDD: Boolean; { combo has edit-like line edit in csDropDownList (Win) and is closed (not DroppedDown }
aGray: Byte;
anyRect: TRect;
aState: TCheckBoxState;
begin { do not call inherited ! }
aDropped:=DroppedDown;
if aDropped and FRejectDropDown then
begin
DroppedDown:=False;
exit; { Exit! }
end;
aEnabled:=IsEnabled;
if not (csDesigning in ComponentState) then
aEnabled:= (aEnabled and PTCheckComboItemState(Items.Objects[Index])^.Enabled);
{$IF DEFINED(LCLWin32) or DEFINED(LCLWin64)}
aFocusedEditableMainItemNoDD := (Focused and (ARect.Left>0) and not aDropped);
{$ELSE}
aFocusedEditableMainItemNoDD := False;
{$ENDIF}
if (ARect.Left=0) or aFocusedEditableMainItemNoDD then
begin
if odSelected in State then
begin
if not aEnabled then
begin
aGray:=ColorToGray(Canvas.Brush.Color);
Canvas.Brush.Color:=RGBToColor(aGray, aGray, aGray);
end;
end else
Canvas.Brush.Color:=clWindow;
Canvas.Brush.Style:=bsSolid;
Canvas.FillRect(ARect);
end;
if not (csDesigning in ComponentState)
then aState:=PTCheckComboItemState(Items.Objects[Index])^.State
else aState:=cbUnchecked;
aDetail:=ThemeServices.GetElementDetails(caCheckThemes
[aEnabled, aState, not aDropped and FCheckHighlight]);
if FNeedMeasure then
begin
FCheckSize:=ThemeServices.GetDetailSize(aDetail);
FTextHeight:=Canvas.TextHeight('ŠjÁÇ');
if not aDropped then
begin
if not FRightToLeft then
begin
FHiLiteLeft:=-1;
FHiLiteRight:=ARect.Right;
end else
begin
FHiLiteLeft:=ARect.Left;
FHiLiteRight:=ARect.Right;
end;
FNeedMeasure := False;
end;
end;
if not FRightToLeft
then anyRect.Left:=ARect.Left+cCheckIndent
else anyRect.Left:=ARect.Right-cCheckIndent-FCheckSize.cx;
anyRect.Right:=anyRect.Left+FCheckSize.cx;
anyRect.Top:=(ARect.Bottom+ARect.Top-FCheckSize.cy) div 2;
anyRect.Bottom:=anyRect.Top+FCheckSize.cy;
ThemeServices.DrawElement(Canvas.Handle, aDetail, anyRect);
Canvas.Brush.Style:=bsClear;
if (not (odSelected in State) or not aDropped) and not aFocusedEditableMainItemNoDD
then Canvas.Font.Color:=clWindowText
else Canvas.Font.Color:=clHighlightText;
if aFocusedEditableMainItemNoDD then
begin
LCLIntf.SetBkColor(Canvas.Handle, ColorToRGB(clBtnFace));
LCLIntf.DrawFocusRect(Canvas.Handle, aRect);
end;
aFlags:=DT_END_ELLIPSIS+DT_VCENTER+DT_SINGLELINE+DT_NOPREFIX;
if not FRightToLeft then
begin
anyRect.Left:=ARect.Left+cCheckIndent+FCheckSize.cx+cTextIndent;
anyRect.Right:=ARect.Right;
end else
begin
anyRect.Right:=anyRect.Left-cTextIndent;
anyRect.Left:=ARect.Left;
aFlags:=aFlags or DT_RIGHT or DT_RTLREADING;
end;
anyRect.Top:=(ARect.Top+ARect.Bottom-FTextHeight) div 2;
anyRect.Bottom:=anyRect.Top+FTextHeight;
ThemeServices.DrawText(Canvas, aDetail, Items[Index], anyRect, aFlags, 0);
end;
procedure TCustomCheckCombo.DropDown;
{$IF DEFINED(LCLWin32) or DEFINED(LCLWin64)}
{$ELSE}
var aCursorPos: TPoint;
aRect: TRect;
{$ENDIF}
begin
{$IF DEFINED(LCLWin32) or DEFINED(LCLWin64)}
FRejectDropDown:=False;
{$ELSE}
aCursorPos:=ScreenToControl(Mouse.CursorPos);
aRect:=Rect(FHiLiteLeft, 0, FHiLiteRight, Height);
FRejectDropDown:=PtInRect(aRect, aCursorPos);
{$ENDIF}
if not FRejectDropDown then
begin
inherited DropDown;
FRejectToggleOnSelect:=False;
end else
if ItemEnabled[ItemIndex] then Toggle(ItemIndex);
end;
procedure TCustomCheckCombo.FontChanged(Sender: TObject);
begin
FNeedMeasure:=True;
inherited FontChanged(Sender);
end;
procedure TCustomCheckCombo.InitializeWnd;
begin
inherited InitializeWnd;
FRightToLeft:=IsRightToLeft;
end;
procedure TCustomCheckCombo.InitItemStates;
var i: Integer;
pItemState: PTCheckComboItemState;
begin
for i:=0 to Items.Count-1 do
begin
pItemState:=new(PTCheckComboItemState);
pItemState^.Enabled:=True;
pItemState^.State:=cbUnchecked;
pItemState^.Data:=nil;
Items.Objects[i]:=TObject(pItemState);
end;
end;
procedure TCustomCheckCombo.KeyDown(var Key: Word; Shift: TShiftState);
begin
case Key of
VK_RETURN:
begin
if not DroppedDown then
begin
DroppedDown:=True;
Key:=0;
end else
begin
if (ItemIndex>=0) and ItemEnabled[ItemIndex] then
begin
Toggle(ItemIndex);
Key:=0;
DroppedDown:=False;
end;
end;
end;
VK_SPACE:
begin
if (ItemIndex>=0) and ItemEnabled[ItemIndex] then
begin
Toggle(ItemIndex);
Key:=0;
if DroppedDown then DroppedDown:=False;
end;
end;
end;
inherited KeyDown(Key, Shift);
end;
procedure TCustomCheckCombo.Loaded;
begin
inherited Loaded;
InitItemStates;
end;
procedure TCustomCheckCombo.MouseLeave;
begin
FCheckHighlight:=False;
inherited MouseLeave;
end;
procedure TCustomCheckCombo.MouseMove(Shift: TShiftState; X, Y: Integer);
var aHighlight: Boolean;
begin
inherited MouseMove(Shift, X, Y);
aHighlight:= ((X>FHiLiteLeft) and (X<FHiLiteRight));
if aHighlight<>FCheckHighlight then
begin
FCheckHighlight:=aHighlight;
Invalidate;
end;
end;
procedure TCustomCheckCombo.Select;
begin
inherited Select;
{$IF DEFINED(LCLWin32) or DEFINED(LCLWin64)}
if DroppedDown then FRejectToggleOnSelect:=True;
{$ENDIF}
if not FRejectToggleOnSelect then
begin
if ItemEnabled[ItemIndex] then Toggle(ItemIndex);
FRejectToggleOnSelect:=True;
end;
end;
procedure TCustomCheckCombo.SetItemHeight(const AValue: Integer);
begin
inherited SetItemHeight(AValue);
FNeedMeasure:=True;
end;
procedure TCustomCheckCombo.Toggle(AIndex: Integer);
const caNewStateMap: array [TCheckBoxState, Boolean] of TCheckBoxState =
{ False (AllowGrayed) True }
((cbChecked, cbGrayed), { cbUnchecked }
(cbUnChecked, cbUnChecked), { cbChecked }
(cbChecked, cbChecked)); { cbGrayed }
begin
State[AIndex]:=caNewStateMap[State[AIndex], AllowGrayed];
end;
{ TCustomCheckCombo.Getters and Setters }
function TCustomCheckCombo.GetChecked(AIndex: Integer): Boolean;
begin
Result:=(PTCheckComboItemState(Items.Objects[AIndex])^.State=cbChecked);
end;
function TCustomCheckCombo.GetCount: Integer;
begin
Result:=Items.Count;
end;
function TCustomCheckCombo.GetItemEnabled(AIndex: Integer): Boolean;
begin
Result:=PTCheckComboItemState(Items.Objects[AIndex])^.Enabled;
end;
function TCustomCheckCombo.GetObject(AIndex: Integer): TObject;
begin
Result:=PTCheckComboItemState(Items.Objects[AIndex])^.Data;
end;
function TCustomCheckCombo.GetState(AIndex: Integer): TCheckBoxState;
begin
Result:=PTCheckComboItemState(Items.Objects[AIndex])^.State;
end;
procedure TCustomCheckCombo.SetChecked(AIndex: Integer; AValue: Boolean);
begin
if AValue=(PTCheckComboItemState(Items.Objects[AIndex])^.State=cbChecked) then exit;
if AValue
then PTCheckComboItemState(Items.Objects[AIndex])^.State:=cbChecked
else PTCheckComboItemState(Items.Objects[AIndex])^.State:=cbUnchecked;
if assigned(FOnItemChange) then FOnItemChange(self, AIndex);
if AIndex=ItemIndex then Invalidate;
end;
procedure TCustomCheckCombo.SetItemEnabled(AIndex: Integer; AValue: Boolean);
begin
if PTCheckComboItemState(Items.Objects[AIndex])^.Enabled=AValue then exit;
PTCheckComboItemState(Items.Objects[AIndex])^.Enabled:=AValue;
if AIndex=ItemIndex then Invalidate;
end;
procedure TCustomCheckCombo.SetObject(AIndex: Integer; AValue: TObject);
begin
PTCheckComboItemState(Items.Objects[AIndex])^.Data:=AValue;
end;
procedure TCustomCheckCombo.SetState(AIndex: Integer; AValue: TCheckBoxState);
begin
if PTCheckComboItemState(Items.Objects[AIndex])^.State=AValue then exit;
PTCheckComboItemState(Items.Objects[AIndex])^.State:=AValue;
if assigned(FOnItemChange) then FOnItemChange(self, AIndex);
if AIndex=ItemIndex then Invalidate;
end;