Mega Code Archive

 
Categories / Delphi / Examples
 

Bitmapcursor

unit MainUnit; //Richard Ebbs //ELIS February 2001 //small test app to work on setting //up drag and drop with a 'bitmap cursor' //WITHOUT using the built in Delphi //StartDrag, DragOver or DragDrop event //handlers... //thrown together very quickly!!! interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, Buttons, StdCtrls; const zoomIncrement = 1.1; origScaleDownFactor = 0.5; origTopLeftX = 50; origTopLeftY = 50; WeeBoxSize = 10; type TCursorBitMapRect = record Left: Integer; Right: Integer; Top: Integer; Bottom: Integer; //'cursor X to bitMap //top left X' distance... cXtoTlX: Integer; //'cursor Y to bitMap //top left Y' distance... cYtoTlY: Integer; end; type TMainForm = class(TForm) TopPanel: TPanel; DrawArea: TImage; procedure DrawAreaMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure DrawAreaMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure DrawAreaMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ScaleBitMapToSize(var anyBitMap: Graphics.TBitMap; newWidth, newHeight: Integer); function IsClickInsideRect(xPos, yPos: Integer; theRect: TCursorBitMapRect): Boolean; procedure SetImageExtents; procedure FillDrawArea; procedure LoadBitMapFromDisk; procedure SetOriginalBitMapScale; procedure DrawWeeBoxAtPoint(thisCanvas: TCanvas; ptToDrawNear: TPoint; boxColour: TColor); private //private declarations originalBitMap: Graphics.TBitMap; drawnBitMap: Graphics.TBitMap; currentScale: Real; //'cursor bitmap' rectangle... cBitMapRect: TCursorBitMapRect; drawAreaBitMap: Graphics.TBitMap; cursorBitMap: Graphics.TBitMap; dragInProgress: Boolean; public //public declarations end; var MainForm: TMainForm; implementation uses TempUnit; {$R *.DFM} ///////////////////////////////////////////////////// procedure TMainForm.DrawAreaMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var destRect: TRect; cornerPt: TPoint; sourceRect: TRect; begin if (IsClickInsideRect(X, Y, cBitMapRect)) then begin //make a bitMap out of the area of the TImage where the bitmap //is currently drawn (identified by the coordinates of cBitMapRect)... destRect.Left := 0; destRect.Top := 0; //get the width and height of the bitmap from cBitMapRect... destRect.Right := (cBitMapRect.Right - cBitMapRect.Left); destRect.Bottom := (cBitMapRect.Bottom - cBitMapRect.Top); cursorBitMap.Width := destRect.Right; cursorBitMap.Height := destRect.Bottom; sourceRect.Left := cBitMapRect.Left; sourceRect.Top := cBitMapRect.Top; sourceRect.Bottom := cBitMapRect.Bottom; sourceRect.Right := cBitMapRect.Right; cursorBitMap.Canvas.CopyRect(destRect, DrawArea.Canvas, sourceRect); //if you want to verify that you've got a valid cursorBitMap at this //point you can uncomment out the two lines below and show it on the //form... //TempForm.SetDrawAreaPicture(cursorBitMap); //TempForm.ShowModal; dragInProgress := True; //copy the whole of the drawing area to a temporary bitmap... drawAreaBitMap.Width := DrawArea.Width; drawAreaBitMap.Height := DrawArea.Height; drawAreaBitMap.Canvas.Draw(0, 0, DrawArea.Picture.Graphic); //set up 'selection' of some kind so that we can i) draw //the 'selection' somehow, but then, ii) later, we can //make sure we only do a 'drag' if the user moves the mouse //more than some specified distance... //first draw wee 'selection boxes' at all four corner points: //top left, top right, bottom right and bottom left... cornerPt.x := cBitMapRect.Left; cornerPt.y := cBitMapRect.Top; DrawWeeBoxAtPoint(drawAreaBitMap.Canvas, cornerPt, clRed); cornerPt.x := cBitMapRect.Right; cornerPt.y := cBitMapRect.Top; DrawWeeBoxAtPoint(drawAreaBitMap.Canvas, cornerPt, clRed); cornerPt.x := cBitMapRect.Right; cornerPt.y := cBitMapRect.Bottom; DrawWeeBoxAtPoint(drawAreaBitMap.Canvas, cornerPt, clRed); cornerPt.x := cBitMapRect.Left; cornerPt.y := cBitMapRect.Bottom; DrawWeeBoxAtPoint(drawAreaBitMap.Canvas, cornerPt, clRed); DrawArea.Canvas.Draw(0, 0, drawAreaBitMap); //store the distances between mouseDown (aka cursor) //X,Y's and the cBitMapRect top left X,Ys so that we //can use these values later in MouseMove... cBitMapRect.cXtoTlX := (X - cBitMapRect.Left); cBitMapRect.cYtoTlY := (Y - cBitMapRect.Top); end; end; //////////////////////////////////////////////////////////////////////// procedure TMainForm.DrawAreaMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var cursorXOffset: Integer; cursorYOffset: Integer; begin if (dragInProgress = True) then begin DrawArea.Canvas.Draw(0, 0, drawAreaBitMap); cursorXOffset := cBitMapRect.cXtoTlX; cursorYOffset := cBitMapRect.cYtoTlY; DrawArea.Canvas.Draw((X - cursorXOffset), (Y - cursorYOffset), cursorBitMap); end; end; ///////////////////////////////////////////////////////////////////////// procedure TMainForm.DrawAreaMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var dropTlX: Integer; dropTlY: Integer; bmpWidth: Integer; bmpHeight: Integer; begin if (dragInProgress = True) then begin FillDrawArea; dropTlX := (X - cBitMapRect.cXtoTlX); dropTlY := (Y - cBitMapRect.cYtoTlY); DrawArea.Canvas.Draw(dropTlX, dropTlY, cursorBitMap); //reset the coordinates of the cBitMapRect such //that it stores the new 'drop' position... bmpWidth := (cBitMapRect.Right - cBitMapRect.Left); bmpHeight := (cBitMapRect.Bottom - cBitMapRect.Top); cBitMapRect.Left := dropTlX; cBitMapRect.Right := (dropTlX + bmpWidth); cBitMapRect.Top := dropTlY; cBitMapRect.Bottom := (dropTlY + bmpHeight); dragInProgress := False; end; end; /////////////////////////////////////////////// procedure TMainForm.FormCreate(Sender: TObject); var newWidth: Integer; newHeight: Integer; begin currentScale := 1.0; SetImageExtents; originalBitMap := Graphics.TBitMap.Create; drawnBitMap := Graphics.TBitMap.Create; LoadBitMapFromDisk; SetOriginalBitMapScale; DrawArea.Canvas.Draw(origTopLeftX, origTopLeftY, originalBitMap); KeyPreview := True; drawAreaBitMap := Graphics.TBitMap.Create; cursorBitMap := Graphics.TBitMap.Create; dragInProgress := False; end; //////////////////////////////////////////////// procedure TMainForm.FormDestroy(Sender: TObject); begin originalBitMap.Free; drawnBitMap.Free; cursorBitMap.Free; drawAreaBitMap.Free; end; /////////////////////////////////////////////// procedure TMainForm.FormResize(Sender: TObject); begin if (MainForm.Width > Screen.Width) then MainForm.Width := (Screen.Width - 1); if (MainForm.Height > Screen.Height) then MainForm.Height := (Screen.Height - 1); DrawArea.Width := MainForm.Width; DrawArea.Height := MainForm.Height; end; //////////////////////////////////// procedure TMainForm.SetImageExtents; {sometimes you find that if you put a TImage on a form and use the TImage as a 'draw area' it won't resize properly when the form is resized. This may have to do with only a certain amount of space being reserved for the image in memory (and the values of TImage.Width/Height not always being congruent with 'internal bitmap.width/height'). This procedure attempts to get around these problems as here we expand the image to the screen's width at the outset so that this much maximum space is always available whatever resizing of the image we do later...} begin DrawArea.Width := Screen.Width; DrawArea.Height := Screen.Height; DrawArea.Canvas.MoveTo(0, 0); DrawArea.Canvas.Pen.Color := clWhite; DrawArea.Canvas.LineTo(DrawArea.Width, DrawArea.Height); DrawArea.align := alClient; end; ///////////////////////////////// procedure TMainForm.FillDrawArea; //set the drawing area background //colour to be white var imageRect: TRect; begin with DrawArea.Canvas do begin Brush.Color := clWhite; imageRect.Left := 0; imageRect.Top := 0; imageRect.Right := Screen.Width; imageRect.Bottom := Screen.Height; FillRect(imageRect); end; end; /////////////////////////////////////// procedure TMainForm.LoadBitMapFromDisk; begin originalBitMap.LoadFromFile('Arnolfini.bmp'); end; ////////////////////////////////////////// procedure TMainForm.SetOriginalBitMapScale; var newWidth, newHeight: Integer; begin newWidth := Round(originalBitMap.Width * origScaleDownFactor); newHeight := Round(originalBitMap.Height * origScaleDownFactor); ScaleBitMapToSize(originalBitMap, newWidth, newHeight); cBitMapRect.Left := origTopLeftX; cBitMapRect.Top := origTopLeftY; cBitMapRect.Right := (cBitMapRect.Left + newWidth); cBitMapRect.Bottom := (cBitMapRect.Top + newHeight); end; ///////////////////////////////////////////////////////////////////// procedure TMainForm.ScaleBitMapToSize(var anyBitMap: Graphics.TBitMap; newWidth, newHeight: Integer); //scale the passed bitmap according to the width and height dimensions //passed in... var tempBitMap: TBitMap; newRect: TRect; begin tempBitMap := TBitMap.Create; newRect.Left := 0; newRect.Right := newWidth; newRect.Top := 0; newRect.Bottom := newHeight; tempBitMap.Width := newWidth; tempBitMap.Height := newHeight; tempBitMap.Canvas.StretchDraw(newRect, anyBitMap); anyBitMap.Width := tempBitMap.Width; anyBitMap.Height := tempBitMap.Height; anyBitMap.Assign(tempBitMap); tempBitMap.Free; end; //////////////////////////////////////////////////////////////////////////////////////// function TMainForm.IsClickInsideRect(xPos, yPos: Integer; theRect: TCursorBitMapRect): Boolean; //reusable function to check if the passed in coordinate identified by X and Y is //within the rectangle passed in: return True if so; return False if not... var inXRange: Boolean; inYRange: Boolean; begin inXRange := False; inYRange := False; if ((xPos > cBitMapRect.Left) and (xPos < cBitMapRect.Right)) then begin inXRange := True; end; if ((yPos > cBitMapRect.Top) and (yPos < cBitMapRect.Bottom)) then begin inYRange := True; end; if ((inXRange = True) and (inYRange = True)) then Result := True else Result := False; end; /////////////////////////////////////////////////////////////////////////////// procedure TMainForm.DrawWeeBoxAtPoint(thisCanvas: TCanvas; ptToDrawNear: TPoint; boxColour: TColor); //draw a tiny square in the passed in colour that is WeeBoxSize pixels above, //right, below and left of the point passed in. Call this proc to draw boxes //at the corners of selected entities drawn on a TImage, for instance... var scrOriginX: Integer; scrOriginY: Integer; begin thisCanvas.Pen.Width := 1; thisCanvas.Pen.Color := boxColour; thisCanvas.MoveTo(Round(ptToDrawNear.x - WeeBoxSize), Round(ptToDrawNear.y - WeeBoxSize)); thisCanvas.LineTo(Round(ptToDrawNear.x + WeeBoxSize), Round(ptToDrawNear.y - WeeBoxSize)); thisCanvas.LineTo(Round(ptToDrawNear.x + WeeBoxSize), Round(ptToDrawNear.y + WeeBoxSize)); thisCanvas.LineTo(Round(ptToDrawNear.x - WeeBoxSize), Round(ptToDrawNear.y + WeeBoxSize)); thisCanvas.LineTo(Round(ptToDrawNear.x - WeeBoxSize), Round(ptToDrawNear.y - WeeBoxSize)); end; end.