home *** CD-ROM | disk | FTP | other *** search
- {***************************************************************
- *
- * Unit Name: DragDropListBox
- * Version : 2.8
- * Date : 1998/11/18
- * Purpose : Enhanced Listbox that show the bitmap items, allow
- * drag-drop operation to change the order of Listbox
- * items and move items between Listboxes.
- * Author : Vincent Huang
- * E-Mail : mac@lion.syscom.com.tw
- * History :
- * 1.5 First release.
- * 2.0 Allow drag-drop among multiple TDragDropListBox.
- * Property 'EnableDragDrop' is renamed to 'DragDropEnabled'.
- * Property 'DragDropInsert' added.
- * Property 'DragDropDelete' added.
- * 2.5 Implement the bimap cursor using TImageList.BeginDrag.
- * 2.6 Fix bug when the drag out another DragDropListBox.
- * 2.7 Utilize TDragControlObject to handle bitmap cursor.
- * Miltiple selection support.
- * Event OnGetDragImageList added, allow user to specify the
- * custommized drag image.
- * Method InsertItems added, allow trigger items moving between
- * listboxes via program.
- * 2.8 Add support for showing bitmap in front of ListBox Item using
- * TImageList. Use it just like the way you use TTreeview.
- * PS: the feature is added because one Delphi component web site
- * add this feature to version 1.5, though it's never
- * supported. Now, you really got it. :)
- * If there is no feature request, there will be only new
- * bug-fixed version from now on. To get new copy, you may
- * check the Delphi Super Page. If you e-mail me, I'll add
- * you to my TDragDropListBox mailing-list. :)
- * Comments : For use with Delphi 2,3,4 and C++ Builder 3.
- * This component is absolutely free. if you use this
- * component, please e-mail me with any kind of
- * comments about this component. I'll inform you about
- * the new version info when avaiable.
- * Usage : set the 'DragDropEnable' to True and it works for you.
- * If DragDropInsert is False, the new item won't be added
- * and the insert position line won't be drawn.
- * If DragDropDelete is False, the dragged item won't be
- * deleted after dropped.
- * To show the dragging image on other control, you have to
- * add the following line in FormShow or somewhere else before
- * the drag event happens.
- *
- * CONTROL_NAME.ControlStyle :=
- * CONTROL_NAME.ControlStyle + [csDisplayDragImage];
- *
- * Bugs : Most of the time, this component works fine. In one of
- * my project, it crash the Delphi 4.02 in debug mode
- * when the drag start but still works fine at run-time
- * (non-debug mode). It crashed at line 8005 of Controls.pas
- * while calling ImageList_DragEnter. :( I'm almost sure it's
- * a bug of either Microsoft's comctl32.dll or Delphi 4.02,
- * not mine. :)
- * PS : This component is to my beloved Daphne, though for
- * some reason we can't be together.
- *
- ****************************************************************}
-
- unit DragDropListBox;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, extctrls
- {$IFDEF VER120}
- ,imgList
- {$ENDIF}
- ;
- type
- TScrollDriection = (sdNone, sdUp, sdDown); // automatically scolling direction
-
- {$IFDEF VER120}
- TGetDragImageListEvent = procedure (Sender: TObject; var ImageList: TDragImageList; var Index, HotSpotX, HotSpotY: Integer) of Object;
- {$ELSE}
- TGetDragImageListEvent = procedure (Sender: TObject; var ImageList: TCustomImageList; var Index, HotSpotX, HotSpotY: Integer) of Object;
- {$ENDIF}
- TGetIntegerEvent = procedure (Sender: TObject; Index: Integer; var ImageIndex: Integer) of Object;
-
- // Delphi 2 made a mistake in TDragControlObject declearation. In line 244 to 252 of controls.pas,
- // the protected and public section should be exchanged. To keep compatible with Delphi 2, This
- // class inherited from TDragControlObject is used to override the member visibility bug.
- THackDragListBoxObject = class(TDragControlObject);
-
- TDragDropListBox = class(TCustomListBox)
- private
- FDragDropEnabled: Boolean; // is the drag-drop functionality enabled ?
- FDragDropInsert: Boolean; // does this DragDropListBox allow insert ?
- FDragDropDelete: Boolean; // does this DragDropListBox allow dlete ?
- FNewItemIndex: Integer; // insert position caculated from the mouse position
- FImages: TCustomImageList; // provide the item bitmap
- FImageChangeLink: TChangeLink;
- FTimer: TTimer; // automatically scroll mechanism
- FScroll: TScrollDriection; // scroll direction of automatically scrolling
- FDragSource: TObject; // used in Timer.OnTrigger to identify the DragSource
- DragControlObject: THackDragListBoxObject; // the DragObject used in this component
- {$IFDEF VER120}
- FDragImage: TDragImageList; // the drag bitmap
- {$ELSE}
- FDragImage: TCustomImageList; // the drag bitmap
- {$ENDIF}
- FFreeDragImageListNeeded: Boolean;
- FOnGetDragImageList: TGetDragImageListEvent; // allow user to provide the drag image
- FOnGetImageIndex: TGetIntegerEvent; // allow user to specify item bitmap if ImageList provided
- procedure DrawLine; // draw or clear the insert position line
- {$IFDEF VER120}
- procedure DefaultGetDragImage(var ImageList: TDragImageList; var Index, HotSpotX, HotSpotY: Integer);
- {$ELSE}
- procedure DefaultGetDragImage(var ImageList: TCustomImageList; var Index, HotSpotX, HotSpotY: Integer);
- {$ENDIF}
- procedure ImageListChange(Sender: TObject);
- procedure SetImages(Value: TCustomImageList);
- procedure TimerTriggered(Sender: TObject); // perform the automatically scrolling
- protected
- procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
- procedure DoStartDrag(var DragObject: TDragObject); override;
- procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); override;
- procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
- {$IFDEF VER120}
- function GetDragImages: TDragImageList; override;
- {$ELSE}
- function GetDragImages: TCustomImageList; override;
- {$ENDIF}
- procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetImageList;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DragDrop(Source: TObject; X, Y: Integer); override;
- procedure InsertItems(SourceBox: TDragDropListBox; PosIndex: Integer);
- published
- property DragDropDelete: Boolean read FDragDropDelete write FDragDropDelete default False;
- property DragDropEnabled: Boolean read FDragDropEnabled write FDragDropEnabled default False;
- property DragDropInsert: Boolean read FDragDropInsert write FDragDropInsert default False;
- property Images: TCustomImageList read FImages write SetImages;
- property OnGetDragImageList: TGetDragImageListEvent read FOnGetDragImageList write FOnGetDragImageList;
- property OnGetImageIndex: TGetIntegerEvent read FOnGetImageIndex write FOnGetImageIndex;
- // the following lines are copyright of Inprise Inc.
- {$IFDEF VER120} // Delphi 4
- property Align;
- property Anchors;
- property BiDiMode;
- property BorderStyle;
- property Color;
- property Columns;
- property Constraints;
- property Ctl3D;
- property DragCursor;
- property DragKind;
- property DragMode;
- property Enabled;
- property ExtendedSelect;
- property Font;
- property ImeMode;
- property ImeName;
- property IntegralHeight;
- property ItemHeight;
- property Items;
- property MultiSelect;
- property ParentBiDiMode;
- property ParentColor;
- property ParentCtl3D;
- property ParentFont;
- property ParentShowHint;
- property PopupMenu;
- property ShowHint;
- property Sorted;
- property Style;
- property TabOrder;
- property TabStop;
- property TabWidth;
- property Visible;
- property OnClick;
- property OnDblClick;
- property OnDragDrop;
- property OnDragOver;
- property OnDrawItem;
- property OnEndDock;
- property OnEndDrag;
- property OnEnter;
- property OnExit;
- property OnKeyDown;
- property OnKeyPress;
- property OnKeyUp;
- property OnMeasureItem;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnStartDock;
- property OnStartDrag;
- {$ENDIF}
- {$IFDEF VER110} // C++ Builder 3
- property Align;
- property BorderStyle;
- property Color;
- property Columns;
- property Ctl3D;
- property DragCursor;
- property DragMode;
- property Enabled;
- property ExtendedSelect;
- property Font;
- property ImeMode;
- property ImeName;
- property IntegralHeight;
- property ItemHeight;
- property Items;
- property MultiSelect;
- property ParentColor;
- property ParentCtl3D;
- property ParentFont;
- property ParentShowHint;
- property PopupMenu;
- property ShowHint;
- property Sorted;
- property Style;
- property TabOrder;
- property TabStop;
- property TabWidth;
- property Visible;
- property OnClick;
- property OnDblClick;
- property OnDragDrop;
- property OnDragOver;
- property OnDrawItem;
- property OnEndDrag;
- property OnEnter;
- property OnExit;
- property OnKeyDown;
- property OnKeyPress;
- property OnKeyUp;
- property OnMeasureItem;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnStartDrag;
- {$ENDIF}
- {$IFDEF VER100} // Delphi 3
- property Align;
- property BorderStyle;
- property Color;
- property Columns;
- property Ctl3D;
- property DragCursor;
- property DragMode;
- property Enabled;
- property ExtendedSelect;
- property Font;
- property ImeMode;
- property ImeName;
- property IntegralHeight;
- property ItemHeight;
- property Items;
- property MultiSelect;
- property ParentColor;
- property ParentCtl3D;
- property ParentFont;
- property ParentShowHint;
- property PopupMenu;
- property ShowHint;
- property Sorted;
- property Style;
- property TabOrder;
- property TabStop;
- property TabWidth;
- property Visible;
- property OnClick;
- property OnDblClick;
- property OnDragDrop;
- property OnDragOver;
- property OnDrawItem;
- property OnEndDrag;
- property OnEnter;
- property OnExit;
- property OnKeyDown;
- property OnKeyPress;
- property OnKeyUp;
- property OnMeasureItem;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnStartDrag;
- {$ENDIF}
- {$IFDEF VER90} // Delphi 2
- property Align;
- property BorderStyle;
- property Color;
- property Columns;
- property Ctl3D;
- property DragCursor;
- property DragMode;
- property Enabled;
- property ExtendedSelect;
- property Font;
- property IntegralHeight;
- property ItemHeight;
- property Items;
- property MultiSelect;
- property ParentColor;
- property ParentCtl3D;
- property ParentFont;
- property ParentShowHint;
- property PopupMenu;
- property ShowHint;
- property Sorted;
- property Style;
- property TabOrder;
- property TabStop;
- property TabWidth;
- property Visible;
- property OnClick;
- property OnDblClick;
- property OnDragDrop;
- property OnDragOver;
- property OnDrawItem;
- property OnEndDrag;
- property OnEnter;
- property OnExit;
- property OnKeyDown;
- property OnKeyPress;
- property OnKeyUp;
- property OnMeasureItem;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnStartDrag;
- {$ENDIF}
- // the above lines are copyright of Inprise Inc.
- end;
-
- procedure Register;
-
- implementation
- uses Math, Commctrl;
-
- procedure Register;
- begin
- RegisterComponents('VincentSoft', [TDragDropListBox]);
- end;
-
- {$IFNDEF VER120} // not Delphi 4
- function Max(A,B: Integer): Integer;
- begin
- if A > B then
- Result := A
- else
- Result := B;
- end;
-
- function Min(A,B: Integer): Integer;
- begin
- if A < B then
- Result := A
- else
- Result := B;
- end;
- {$ENDIF}
-
- constructor TDragDropListBox.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FImages := nil;
- FImageChangeLink := TChangeLink.Create;
- FImageChangeLink.OnChange := ImageListChange;
- if not (csDesigning in ComponentState) then
- begin
- ControlStyle := ControlStyle + [csDisplayDragImage];
- DragControlObject := THackDragListBoxObject.Create(Self);
- FFreeDragImageListNeeded := False;
- FDragImage := nil;
- FNewItemIndex := Low(Integer);
- FTimer := TTimer.Create(AOwner);
- FTimer.Enabled := False;
- FTimer.OnTimer := TimerTriggered;
- FTimer.Interval := 250;
- end;
- end;
-
- destructor TDragDropListBox.Destroy;
- begin
- if Assigned(FTimer) then
- FTimer.Free;
- if Assigned(DragControlObject) then
- begin
- DragControlObject.Free;
- DragControlObject := nil;
- end;
- inherited Destroy;
- end;
-
- procedure TDragDropListBox.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- inherited Notification(AComponent, Operation);
- if Operation = opRemove then
- if AComponent = Images then Images := nil;
- end;
-
- { ** Bitmap Item that Utilize the ImageList ** }
-
- { }
- procedure TDragDropListBox.SetImages(Value: TCustomImageList);
- begin
- if Images <> nil then
- Images.UnRegisterChanges(FImageChangeLink);
- FImages := Value;
- if Images <> nil then
- begin
- Images.RegisterChanges(FImageChangeLink);
- Images.FreeNotification(Self)
- end;
- SetImageList;
- if (Images <> nil) and (Style=lbStandard) then
- Style := lbOwnerDrawFixed;
- end;
-
- { }
- procedure TDragDropListBox.SetImageList;
- begin
- Refresh;
- end;
-
- { }
- procedure TDragDropListBox.ImageListChange(Sender: TObject);
- begin
- SetImageList;
- end;
-
- { draw the ListBox item }
- procedure TDragDropListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
- var
- {$IFDEF VER120}
- Flags: Longint;
- {$ENDIF}
- ItemBitmapIndex: Integer;
- begin
- if Assigned(OnDrawItem) then
- OnDrawItem(Self, Index, Rect, State)
- else
- begin
- if Assigned(FImages) then
- begin
- Canvas.FillRect(Rect);
- if Index < Items.Count then
- begin
- ItemBitmapIndex := -1;
- // draw bitmap
- if Assigned(OnGetImageIndex) then
- OnGetImageIndex(Self, Index, ItemBitmapIndex);
- FImages.Draw(Canvas, Rect.Left+2, Rect.Top+((Rect.Bottom-Rect.Top-TImageList(FImages).Height) div 2), ItemBitmapIndex);
- Rect.Left := Rect.Left+(2+TImageList(FImages).Width);
- // draw text
- {$IFDEF VER120}
- Flags := DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER);
- if not UseRightToLeftAlignment then
- Inc(Rect.Left, 2)
- else
- Dec(Rect.Right, 2);
- DrawText(Canvas.Handle, PChar(Items[Index]), Length(Items[Index]), Rect,
- Flags);
- {$ELSE}
- Canvas.FillRect(Rect);
- if Index < Items.Count then
- Canvas.TextOut(Rect.Left + 2, Rect.Top+((Rect.Bottom-Rect.Top-Canvas.TextHeight(Items[Index])) div 2), Items[Index]);
- {$ENDIF}
- end;
- end
- else
- inherited;
- end;
- end;
-
- { ** Drag and Drop Support that Utilize the TDragControlObject ** }
-
- { draw or clear the position line }
- procedure TDragDropListBox.DrawLine;
- var
- PenMode: TPenMode;
- PenWidth: Integer;
- begin
- if (FNewItemIndex<>Low(Integer)) // initial status, draw line here is meangless
- and DragDropInsert then // insert not allowed, draw line here is meangless
- begin
- PenWidth := Canvas.Pen.Width;
- PenMode := Canvas.Pen.Mode;
- try
- Canvas.Pen.Width := 2;
- Canvas.Pen.Mode := pmNot;
- Canvas.PolyLine([Point(0, FNewItemIndex), Point(Width, FNewItemIndex)]);
- finally
- Canvas.Pen.Width := PenWidth;
- Canvas.Pen.Mode := PenMode;
- end;
- end;
- end;
-
- { using Timer to perform the automatically scrolling }
- procedure TDragDropListBox.TimerTriggered(Sender: TObject);
- var
- NewTopIndex : Integer;
- begin
- // calculate the new TopIndex of ListBox
- case FScroll of
- sdDown: NewTopIndex := Min(TopIndex+1, Items.Count-(Height div ItemHeight));
- sdUp: NewTopIndex := Max(TopIndex-1, 0);
- else
- Exit;
- end;
- // perform the scrolling
- if NewTopIndex <> TopIndex then
- begin
- // do automatically scrolling
- TDragDropListBox(FDragSource).DragControlObject.HideDragImage;
- DrawLine; // clear insert position Line
- TopIndex := NewTopIndex; // scroll
- DrawLine; // draw insert position line
- TDragDropListBox(FDragSource).DragControlObject.ShowDragImage;
- end;
- end;
-
- { }
- {$IFDEF VER120}
- function TDragDropListBox.GetDragImages: TDragImageList;
- {$ELSE}
- function TDragDropListBox.GetDragImages: TCustomImageList;
- {$ENDIF}
- begin
- Result := FDragImage;
- end;
-
- {}
- {$IFDEF VER120}
- procedure TDragDropListBox.DefaultGetDragImage(var ImageList: TDragImageList; var Index, HotSpotX, HotSpotY: Integer);
- {$ELSE}
- procedure TDragDropListBox.DefaultGetDragImage(var ImageList: TCustomImageList; var Index, HotSpotX, HotSpotY: Integer);
- {$ENDIF}
- var
- SelectedIndex : Integer;
- RectItem: TRect;
- ItemSelected : Boolean;
- Bitmap: TBitmap;
- begin
- // Get the listbox item bitmap
- RectItem := ItemRect(ItemIndex);
- RectItem := Rect(RectItem.Left+1, RectItem.Top+1, RectItem.Right-1, RectItem.Bottom-1);
- Bitmap := TBitmap.Create;
- try
- Bitmap.Height := RectItem.Bottom-RectItem.Top;
- Bitmap.Width := RectItem.Right-RectItem.Left;
- // de-hilight the selection temporary to get the normal bitmap
- if MultiSelect then
- begin
- ItemSelected := Selected[ItemIndex];
- Selected[ItemIndex] := False;
- Update;
- Bitmap.Canvas.CopyRect(Bounds(0, 0, Bitmap.Width, Bitmap.Height), Canvas, RectItem);
- Selected[ItemIndex] := ItemSelected;
- Update;
- end
- else
- begin
- SelectedIndex := ItemIndex;
- ItemIndex := -1;
- Bitmap.Canvas.CopyRect(Bounds(0, 0, Bitmap.Width, Bitmap.Height), Canvas, RectItem);
- ItemIndex := SelectedIndex;
- end;
- if Assigned(FDragImage) and (FFreeDragImageListNeeded) then
- begin
- FDragImage.Free;
- FDragImage := nil;
- end;
- {$IFDEF VER120}
- ImageList := TDragImageList.CreateSize(Bitmap.Width, Bitmap.Height);
- {$ELSE}
- ImageList := TCustomImageList.CreateSize(Bitmap.Width, Bitmap.Height);
- {$ENDIF}
- FFreeDragImageListNeeded := True;
- if SelCount > 1 then // if MultiSlect=False, SelCount always return -1
- DragCursor := crMultiDrag
- else
- DragCursor := crDrag;
- ImageList.AddMasked(Bitmap, Color);
- Index := 0;
- HotSpotX := 2;
- HotSpotY := 2;
- finally
- Bitmap.Free;
- end;
- end;
-
- { }
- procedure TDragDropListBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- var
- Index, HotSpotX, HotSpotY: Integer;
- begin
- inherited;
- if DragDropEnabled and not Dragging and (Button=mbLeft) then
- // there must be some selection to drag
- if (not MultiSelect and (ItemAtPos(Point(X, Y), True)<>-1)) or (MultiSelect and (SelCount>0)) then
- // use DragDetect to avoid the side effect of unnecessary BeginDrag, immediate=False doesn't work. :(
- if DragDetect(Handle, Self.ClientToScreen(Point(X, Y))) then
- begin
- // get DragImageList
- if Assigned(FOnGetDragImageList) then
- FOnGetDragImageList(Self, FDragImage, Index, HotSpotX, HotSpotY)
- else
- DefaultGetDragImage(FDragImage, Index, HotSpotX, HotSpotY);
- if Assigned(FDragImage) then
- FDragImage.SetDragImage(Index, HotSpotX, HotSpotY);
- BeginDrag(False);
- end;
- end;
-
- { }
- procedure TDragDropListBox.DoStartDrag(var DragObject: TDragObject);
- begin
- DragObject := DragControlObject;
- inherited;
- end;
-
- { }
- procedure TDragDropListBox.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
- var
- ItemIndexY: Integer;
- SourceBox: TDragDropListBox;
- begin
- // Trigger user-defined OnDragOver, the following is a modified inherited call
- if (Source is TDragControlObject) then Source := THackDragListBoxObject(Source).Control;
- Accept := (Source is TDragDropListBox);
- if Assigned(OnDragOver) then
- OnDragOver(Self, Source, X, Y, State, Accept);
- // Processing DragOver behavior of TDragDropListBox
- if not ((Source is TDragDropListBox) and DragDropEnabled and TDragDropListBox(Source).DragDropEnabled)then exit;
- if Accept then
- begin
- SourceBox := TDragDropListBox(Source);
- if not SourceBox.DragDropEnabled then exit;
- case State of
- dsDragMove:
- begin
- // set direction of automatically scrolling
- if (Y <= ItemHeight/2) then
- FScroll := sdUp
- else if (Y >= ClientHeight-ItemHeight/2) then
- FScroll := sdDown
- else
- FScroll := sdNone;
- FTimer.Enabled := (DragDropInsert) and (FScroll<>sdNone); // enable automatically scrolling
- ItemIndexY := Min(Round(Y/ItemHeight)*ItemHeight, Items.Count*ItemHeight+1); // calculate new position
- if ItemIndexY <> FNewItemIndex then // if new position changed
- begin
- SourceBox.DragControlObject.HideDragImage;
- DrawLine; // clear old line
- FNewItemIndex := ItemIndexY; // new insert position
- DrawLine; // draw new line
- SourceBox.DragControlObject.ShowDragImage;
- end;
- end;
- dsDragLeave:
- begin
- FDragSource := nil;
- FTimer.Enabled := False; // turn off automatically scrolling
- SourceBox.DragControlObject.HideDragImage;
- DrawLine; // clear the new position line
- SourceBox.DragControlObject.ShowDragImage;
- end;
- dsDragEnter:
- begin
- FDragSource := SourceBox;
- FNewItemIndex := Low(Integer); // initial status
- end;
- end;
- end;
- end;
-
- { }
- procedure TDragDropListBox.DragDrop(Source: TObject; X, Y: Integer);
- var
- NewItemIndex: Integer;
- begin
- inherited; // perform the user-defined OnDragDrop event handler
- if (Source is TDragControlObject) then Source := THackDragListBoxObject(Source).Control;
- if not ((Source is TDragDropListBox) and DragDropEnabled and TDragDropListBox(Source).DragDropEnabled) then exit;
- FTimer.Enabled := False; // turn off automatically scrolling
- // caculate ItemIndex of the insert position
- if FScroll = sdDown then FNewItemIndex := FNewItemIndex-(ItemHeight div 2); // at the scroll down position, ItemAtPos=-1
- NewItemIndex := ItemAtPos(Point(0, FNewItemIndex), False);
- if FScroll = sdDown then Inc(NewItemIndex); // at the scroll down position, ItemIndex has to be adjusted
- // perform the insert operation
- try
- InsertItems(TDragDropListBox(Source), NewItemIndex);
- finally
- FNewItemIndex := Low(Integer);
- end;
- end;
-
- { }
- procedure TDragDropListBox.DoEndDrag(Target: TObject; X, Y: Integer);
- begin
- FNewItemIndex := Low(Integer);
- if Assigned(FDragImage) and (FFreeDragImageListNeeded) then
- begin
- FDragImage.Free;
- FDragImage := nil;
- end;
- inherited; // perform the user-defined OnEndDrag event handler
- end;
-
- { }
- procedure TDragDropListBox.InsertItems(SourceBox: TDragDropListBox; PosIndex: Integer);
- var
- i, SelectItemIndex, DeletedCountBeforeInsertPoint: Integer;
- SelectedItems: TStringList;
- begin
- if (SourceBox.MultiSelect and (SourceBox.SelCount<1)) or
- (not SourceBox.MultiSelect and (SourceBox.ItemIndex=-1)) then
- exit;
- DeletedCountBeforeInsertPoint := 0;
- SelectItemIndex := 0;
- SelectedItems := TStringList.Create;
- try
- // build the selection list
- SelectedItems.BeginUpdate;
- for i:=SourceBox.Items.Count-1 downto 0 do
- if SourceBox.Selected[i] then
- begin
- SelectedItems.AddObject(SourceBox.Items[i], SourceBox.Items.Objects[i]);
- if (SourceBox=Self) and (i<PosIndex) then Inc(DeletedCountBeforeInsertPoint);
- if i = SourceBox.ItemIndex then SelectItemIndex := SelectedItems.Count-1;
- end;
- SelectedItems.EndUpdate;
- // insert the selection into target
- if Self.DragDropInsert then
- begin
- Self.Items.BeginUpdate;
- for i:= 0 to SelectedItems.Count-1 do
- Self.Items.InsertObject(PosIndex, SelectedItems.Strings[i], SelectedItems.Objects[i]);
- Self.Items.EndUpdate;
- SourceBox.Items.BeginUpdate;
- end;
- // remove the selection from source
- if SourceBox.DragDropDelete then
- begin
- for i:=SourceBox.Items.Count-1 downto 0 do
- if SourceBox.Selected[i] then
- SourceBox.Items.Delete(i);
- SourceBox.Items.EndUpdate;
- end;
- // set the selection in the target to the new inserted items
- if (Self.DragDropInsert) and (Self.MultiSelect) then
- for i:=0 to Items.Count-1 do
- Self.Selected[i] := (i>=PosIndex-DeletedCountBeforeInsertPoint) and
- (i<=PosIndex-DeletedCountBeforeInsertPoint+SelectedItems.Count-1);
- // set the current ItemIndex of the source listbox
- if SourceBox.DragDropDelete then
- SourceBox.ItemIndex := Min(SourceBox.ItemIndex, SourceBox.Items.Count-1);
- // set the current ItemIndex of the target listbox to get the correct focused item
- if Self.DragDropInsert then
- Self.ItemIndex := Max(-1, PosIndex-DeletedCountBeforeInsertPoint+SelectedItems.Count-SelectItemIndex-1);
- finally
- SelectedItems.Free;
- end;
- end;
-
- end.
-