home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / RUNIMAGE / DELPHI30 / SOURCE / VCL / CHECKLST.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-03  |  11.5 KB  |  451 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Delphi Visual Component Library                 }
  4. {                                                       }
  5. {       Copyright (c) 1997 Borland International        }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit checklst;
  10.  
  11. interface
  12.  
  13. uses
  14.   Windows, Messages, SysUtils, Classes, Graphics, Controls, 
  15.   StdCtrls;
  16.  
  17. type
  18.   TCheckListBox = class(TCustomListBox)
  19.   private
  20.     FAllowGrayed: Boolean;
  21.     FStandardItemHeight: Integer;
  22.     FOnClickCheck: TNotifyEvent;
  23.     FSaveStates: TList;
  24.     procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
  25.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  26.     procedure ResetItemHeight;
  27.     procedure DrawCheck( R: TRect; AState: TCheckBoxState );
  28.     procedure SetChecked( Index: Integer; Checked: Boolean );
  29.     function GetChecked( Index: Integer ): Boolean;
  30.     procedure SetState( Index: Integer; AState: TCheckBoxState );
  31.     function GetState( Index: Integer ): TCheckBoxState;
  32.     procedure ToggleClickCheck( Index: Integer );
  33.     procedure InvalidateCheck( Index: Integer );
  34.     function CreateWrapper( Index: Integer ): TObject;
  35.     function ExtractWrapper( Index: Integer ): TObject;
  36.     function GetWrapper( Index: Integer): TObject;
  37.     function HaveWrapper( Index: Integer): Boolean;
  38.   protected
  39.     procedure DrawItem(Index: Integer; Rect: TRect;
  40.       State: TOwnerDrawState); override;
  41.     procedure SetItemData( Index: Integer; AData: LongInt ); override;
  42.     function GetItemData( Index: Integer ): LongInt; override;
  43.     procedure KeyPress(var Key: Char); override;
  44.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  45.       X, Y: Integer); override;
  46.     procedure ResetContent; override;
  47.     procedure DeleteString(Index: Integer); override;
  48.     procedure ClickCheck; dynamic;
  49.     procedure CreateParams(var Params: TCreateParams); override;
  50.     procedure CreateWnd; override;
  51.     procedure DestroyWnd; override;
  52.     function GetCheckWidth: Integer;
  53.   public
  54.     destructor Destroy; override;
  55.     property Checked[Index: Integer]: Boolean read GetChecked write SetChecked;
  56.     property State[Index: Integer]: TCheckBoxState read GetState write SetState;
  57.   published
  58.     property OnClickCheck: TNotifyEvent read FOnClickCheck write FOnClickCheck;
  59.     property Align;
  60.     property AllowGrayed: Boolean read FAllowGrayed write FAllowGrayed default False;
  61.     property BorderStyle;
  62.     property Color;
  63.     property Columns;
  64.     property Ctl3D;
  65.     property DragCursor;
  66.     property DragMode;
  67.     property Enabled;
  68.     //property ExtendedSelect;
  69.     property Font;
  70.     property ImeMode;
  71.     property ImeName;
  72.     property IntegralHeight;
  73.     property ItemHeight;
  74.     property Items;
  75.     //property MultiSelect;
  76.     property ParentColor;
  77.     property ParentCtl3D;
  78.     property ParentFont;
  79.     property ParentShowHint;
  80.     property PopupMenu;
  81.     property ShowHint;
  82.     property Sorted;
  83.     property Style;
  84.     property TabOrder;
  85.     property TabStop;
  86.     property TabWidth;
  87.     property Visible;
  88.     property OnClick;
  89.     property OnDblClick;
  90.     property OnDragDrop;
  91.     property OnDragOver;
  92.     property OnDrawItem;
  93.     property OnEndDrag;
  94.     property OnEnter;
  95.     property OnExit;
  96.     property OnKeyDown;
  97.     property OnKeyPress;
  98.     property OnKeyUp;
  99.     property OnMeasureItem;
  100.     property OnMouseDown;
  101.     property OnMouseMove;
  102.     property OnMouseUp;
  103.     property OnStartDrag;
  104.   end;
  105.  
  106. implementation
  107.  
  108. uses consts;
  109.  
  110. type
  111.  
  112.   TCheckListBoxDataWrapper = class
  113.   private
  114.     FData: LongInt;
  115.     FState: TCheckBoxState;
  116.     procedure SetChecked( Check: Boolean );
  117.     function GetChecked: Boolean;
  118.   public
  119.     class function GetDefaultState: TCheckBoxState;
  120.     property Checked: Boolean read GetChecked write SetChecked;
  121.     property State: TCheckBoxState read FState write FState;
  122.   end;
  123.  
  124.  
  125.  
  126. var
  127.   FCheckWidth, FCheckHeight: Integer;
  128.  
  129. procedure GetCheckSize;
  130. begin
  131.   with TBitmap.Create do
  132.     try
  133.       Handle := LoadBitmap( 0, PChar(32759) );
  134.       FCheckWidth := Width div 4;
  135.       FCheckHeight := Height div 3;
  136.     finally
  137.       Free;
  138.     end;
  139. end;
  140.  
  141. { TCheckListBoxDataWrapper }
  142. procedure TCheckListBoxDataWrapper.SetChecked( Check: Boolean );
  143. begin
  144.   if Check then FState := cbChecked else FState := cbUnchecked;
  145. end;
  146.  
  147. function TCheckListBoxDataWrapper.GetChecked: Boolean;
  148. begin
  149.   Result := FState = cbChecked;
  150. end;
  151.  
  152. class function TCheckListBoxDataWrapper.GetDefaultState: TCheckBoxState;
  153. begin
  154.   Result := cbUnchecked;
  155. end;
  156.  
  157. { TCheckListBox }
  158. destructor TCheckListBox.Destroy;
  159. begin
  160.   FSaveStates.Free;
  161.   inherited;
  162. end;
  163.  
  164. procedure TCheckListBox.CreateWnd;
  165. begin
  166.   inherited CreateWnd;
  167.   if FSaveStates <> nil then
  168.   begin
  169.     FSaveStates.Free;
  170.     FSaveStates := nil;
  171.   end;
  172.   ResetItemHeight;
  173. end;
  174.  
  175. procedure TCheckListBox.DestroyWnd;
  176. var
  177.   I: Integer;
  178.   FWrappers: TList;
  179. begin
  180.   FWrappers := nil;
  181.   if Items.Count > 0 then
  182.   begin
  183.     FSaveStates := TList.Create;
  184.     FWrappers := TList.Create;
  185.     for I := 0 to Items.Count -1 do
  186.     begin
  187.       FSaveStates.Add( TObject( State[I]) );
  188.       FWrappers.Add( ExtractWrapper( I ) );
  189.     end;
  190.   end;
  191.   inherited DestroyWnd;
  192.   if FWrappers <> nil then
  193.   begin
  194.     for I := 0 to FWrappers.Count-1 do
  195.       TCheckListBoxDataWrapper(FWrappers[I]).Free;
  196.     FWrappers.Free;
  197.   end;
  198. end;
  199.  
  200. procedure TCheckListBox.CreateParams(var Params: TCreateParams);
  201. begin
  202.   inherited;
  203.   with Params do
  204.     if Style and (LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE ) = 0 then
  205.       Style := Style or LBS_OWNERDRAWFIXED;
  206. end;
  207.  
  208. function TCheckListBox.GetCheckWidth: Integer;
  209. begin
  210.   Result := FCheckWidth + 2;
  211. end;
  212.  
  213. procedure TCheckListBox.CMFontChanged(var Message: TMessage);
  214. begin
  215.   inherited;
  216.   ResetItemHeight;
  217. end;
  218.  
  219. procedure TCheckListBox.ResetItemHeight;
  220. begin
  221.   if HandleAllocated and (Style = lbStandard) then
  222.   begin
  223.     Canvas.Font := Font;
  224.     FStandardItemHeight := Canvas.TextHeight('Wg');
  225.     Perform(LB_SETITEMHEIGHT, 0, FStandardItemHeight);
  226.   end;
  227. end;
  228.  
  229.  
  230. procedure TCheckListBox.DrawItem(Index: Integer; Rect: TRect;
  231.   State: TOwnerDrawState);
  232. var
  233.   R: TRect;
  234.   SaveEvent: TDrawItemEvent;
  235. begin
  236.  
  237.   if Index < Items.Count then
  238.   begin
  239.     R := Rect;
  240.     R.Right := Rect.Left;
  241.     R.Left := R.Right - GetCheckWidth;
  242.     DrawCheck( R, GetState( Index ) );
  243.   end;
  244.  
  245.   if (Style = lbStandard) and Assigned(OnDrawItem) then
  246.   begin
  247.     // Force lbStandard list to ignore OnDrawItem event.
  248.     SaveEvent := OnDrawItem;
  249.     OnDrawItem := nil;
  250.     try
  251.       inherited;
  252.     finally
  253.       OnDrawItem := SaveEvent;
  254.     end;
  255.   end
  256.   else
  257.     inherited;
  258. end;
  259.  
  260.  
  261. procedure TCheckListBox.CNDrawItem(var Message: TWMDrawItem);
  262. begin 
  263.     with Message.DrawItemStruct^ do
  264.         rcItem.Left := rcItem.Left + GetCheckWidth;
  265.     inherited;
  266. end;
  267.  
  268.  
  269. procedure TCheckListBox.DrawCheck( R: TRect; AState: TCheckBoxState );
  270. var
  271.   DrawState: Integer;
  272.   DrawRect: TRect;
  273. begin
  274.   case AState of
  275.     cbChecked:
  276.       DrawState := DFCS_BUTTONCHECK or DFCS_CHECKED;
  277.     cbUnchecked:
  278.       DrawState := DFCS_BUTTONCHECK;
  279.     else // cbGrayed
  280.       DrawState := DFCS_BUTTON3STATE or DFCS_CHECKED;
  281.   end;
  282.   DrawRect.Left := R.Left + (R.Right - R.Left - FCheckWidth) div 2;
  283.   DrawRect.Top := R.Top + (R.Bottom - R.Top - FCheckWidth) div 2;
  284.   DrawRect.Right := DrawRect.Left + FCheckWidth;
  285.   DrawRect.Bottom := DrawRect.Top + FCheckHeight;
  286.  
  287.   DrawFrameControl( Canvas.Handle,
  288.      DrawRect,  DFC_BUTTON,  DrawState);
  289.  
  290. end;
  291.  
  292.  
  293.  
  294. procedure TCheckListBox.SetChecked( Index: Integer; Checked: Boolean );
  295. begin
  296.   if Checked <> GetChecked( Index ) then
  297.   begin
  298.     TCheckListBoxDataWrapper(GetWrapper(Index)).SetChecked( Checked );
  299.     InvalidateCheck( Index );
  300.   end;
  301. end;
  302.  
  303. procedure TCheckListBox.SetState( Index: Integer; AState: TCheckBoxState );
  304. begin
  305.   if AState <> GetState( Index ) then
  306.   begin
  307.     TCheckListBoxDataWrapper(GetWrapper(Index)).State := AState;
  308.     InvalidateCheck( Index );
  309.   end;
  310. end;
  311.  
  312. procedure TCheckListBox.InvalidateCheck( Index: Integer );
  313. var
  314.   R: TRect;
  315. begin
  316.   R := ItemRect( Index );
  317.   R.Right := R.Left + GetCheckWidth;
  318.   InvalidateRect(Handle, @R, not (csOpaque in ControlStyle));
  319.   UpdateWindow(Handle);
  320. end;
  321.  
  322. function TCheckListBox.GetChecked( Index: Integer ): Boolean;
  323. begin
  324.   if HaveWrapper( Index ) then
  325.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).GetChecked
  326.   else
  327.     Result := False;
  328. end;
  329.  
  330. function TCheckListBox.GetState( Index: Integer ): TCheckBoxState;
  331. begin
  332.   if HaveWrapper( Index ) then
  333.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).State
  334.   else
  335.     Result := TCheckListBoxDataWrapper.GetDefaultState;
  336. end;
  337.  
  338. procedure TCheckListBox.KeyPress(var Key: Char);
  339. begin
  340.   inherited;
  341.   if (Key = ' ') then ToggleClickCheck( ItemIndex );
  342. end;
  343.  
  344. procedure TCheckListBox.MouseDown(Button: TMouseButton; Shift: TShiftState;
  345.       X, Y: Integer);
  346. var
  347.   Index: Integer;
  348. begin
  349.   inherited;
  350.   Index := ItemAtPos(Point(X,Y),True);
  351.   if Index <> -1 then
  352.     if X - ItemRect(Index).Left < GetCheckWidth then
  353.       ToggleClickCheck(Index);
  354. end;
  355.  
  356.  
  357. procedure TCheckListBox.ToggleClickCheck;
  358. var
  359.   State: TCheckBoxState;
  360. begin
  361.   if (Index >= 0) and (Index < Items.Count) then
  362.   begin
  363.     State := Self.State[Index];
  364.     case State of
  365.       cbUnchecked:
  366.         if AllowGrayed then State := cbGrayed else State := cbChecked;
  367.       cbChecked: State := cbUnchecked;
  368.       cbGrayed: State := cbChecked;
  369.     end;
  370.     Self.State[Index] := State;
  371.  
  372.     ClickCheck;
  373.   end;
  374. end;
  375.  
  376. procedure TCheckListBox.ClickCheck;
  377. begin
  378.   if Assigned(FOnClickCheck) then FOnClickCheck(Self);
  379. end;
  380.  
  381. function TCheckListBox.GetItemData(Index: Integer): LongInt;
  382. begin
  383.   Result := 0;
  384.   if HaveWrapper( Index ) then
  385.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).FData;
  386. end;
  387.  
  388. function TCheckListBox.GetWrapper( Index: Integer ): TObject;
  389. begin
  390.   Result := ExtractWrapper( Index );
  391.   if Result = nil then
  392.     Result := CreateWrapper( Index );
  393. end;
  394.  
  395. function TCheckListBox.ExtractWrapper( Index: Integer ): TObject;
  396. begin
  397.   Result := TCheckListBoxDataWrapper(inherited GetItemData( Index ));
  398.   if LB_ERR = Integer(Result) then
  399.     raise EListError.CreateFmt(SListIndexError, [Index]);
  400.   if (Result <> nil) and (not (Result is TCheckListBoxDataWrapper)) then
  401.     Result := nil;
  402. end;
  403.  
  404. function TCheckListBox.CreateWrapper( Index: Integer ): TObject;
  405. begin
  406.   Result := TCheckListBoxDataWrapper.Create;
  407.   inherited SetItemData(Index, LongInt(Result));
  408. end;
  409.  
  410. function TCheckListBox.HaveWrapper( Index: Integer ): Boolean;
  411. begin
  412.   Result := ExtractWrapper( Index ) <> nil;
  413. end;
  414.  
  415. procedure TCheckListBox.SetItemData(Index: Integer; AData: LongInt);
  416. var
  417.   Wrapper: TCheckListBoxDataWrapper;
  418. begin
  419.   Wrapper := TCheckListBoxDataWrapper(GetWrapper( Index ));
  420.   Wrapper.FData := AData;
  421.   if FSaveStates <> nil then
  422.     if FSaveStates.Count > 0 then
  423.     begin
  424.      Wrapper.FState := TCheckBoxState(FSaveStates[0]);
  425.      FSaveStates.Delete(0);
  426.     end;
  427. end;
  428.  
  429.  
  430. procedure TCheckListBox.ResetContent;
  431. var
  432.   I: Integer;
  433. begin
  434.   for I := 0 to Items.Count - 1 do
  435.     if HaveWrapper(I) then
  436.       GetWrapper( I ).Free;
  437.   inherited;
  438. end;
  439.  
  440. procedure TCheckListBox.DeleteString(Index: Integer);
  441. begin
  442.   if HaveWrapper(Index) then
  443.     GetWrapper( Index ).Free;
  444.   inherited;
  445. end;
  446.  
  447. initialization
  448.   GetCheckSize;
  449.  
  450. end.
  451.