Author |
Topic |
|
AndyColmes
USA
351 Posts |
Posted - May 23 2014 : 00:16:44
|
When creating objects of lines, I would like to change the usual black line during drawing. Once the line is drawn, it picks up the color of the ObjPenStyle and ObjPenColor which is fine. It is just the initial drawing that the color is always black which is a problem for grayscale images where the user cannot see what he or she is drawing.
Thanks in advance.
|
|
spetric
Croatia
308 Posts |
Posted - May 28 2014 : 01:34:42
|
Hi Andy.
I haven't find the way to change "temporary" color of line when miPuLine interaction is set.
I don't know if this can help you: sometimes I want to draw multiple objects and "reshape" them on mouse move:
There are actually 3 objects, created in OnMouseDown event: line with arrow, circle and text (angle in degrees).
In OnMouseMove event I'm simple reshaping those objects according to mouse position.
In the same way, you can create simple line in OnMouseDown event (with desired color) and then change the shape of line in OnMouseMove event. |
|
|
AndyColmes
USA
351 Posts |
Posted - May 28 2014 : 07:12:33
|
Hi spetric, thank you for your suggestion which seems interesting. Do you have a simple demo project to demonstrate this? I would really appreciate it. Thanks again for helping out. |
|
|
spetric
Croatia
308 Posts |
Posted - May 28 2014 : 12:31:35
|
I don't have simple demo, but I can extract code from project where I use such kind of manipulation with vectorial objects.
I'll try to prepare code for tomorrow. However, it's in C++, but you'll get the picture. |
|
|
spetric
Croatia
308 Posts |
Posted - May 29 2014 : 06:25:32
|
Here we go. MouseInteract is empty (no miPutLine). On ImageEnVect component (PaintView in code) we have OnMouseDown event and OnMouseMove. I use also OnMouseUp event for rendering purposes, but in your case this isn't obligatory.
Here is mousedown event:
// OnMouseDown event
xDown = PaintView->XScr2Bmp(X);
yDown = PaintView->YScr2Bmp(Y);
// _hobj - private variable
_hobj = PaintView->AddNewObject();
PaintView->ObjKind[_hobj] = iekLINE;
PaintView->ObjBrushStyle[_hobj] = bsSolid;
PaintView->ObjBrushColor[_hobj] = clBlue;
PaintView->ObjEndShape[_hobj] = iesOUTARROW;
//you can neglect upper line
PaintView->ObjTop[_hobj] = yDown;
PaintView->ObjLeft[_hobj] = xDown;
PaintView->ObjWidth[_hobj] = 0;
PaintView->ObjHeight[_hobj] = 0;
PaintView->ObjPenWidth[_hobj] = someWidth;
PaintView->ObjPenColor[_hobj] = someCOlor;
PaintView->ObjStyle[_hobj] = TIEVStyle()<<ievsVisible;
PaintView->ObjName[_hobj] = "someName";
And here is mousemove event:
// OnMouseMove event
xMove = PaintView->XScr2Bmp(X);
yMove = PaintView->YScr2Bmp(Y);
PaintView->ObjWidth[_hobj] = xMove - PaintView->ObjLeft[_hobj];
PaintView->ObjHeight[_hobj] = yMove - PaintView->ObjTop[_hobj];
xDown and yDown can be declared as private variables. I use them when performing object movement across the screen (when shift key is pressed - in onmousemove event).
Hope this helps. |
|
|
w2m
USA
1990 Posts |
|
w2m
USA
1990 Posts |
Posted - May 29 2014 : 10:59:24
|
To change an object after it is created get the selected object and then set the objects parameters:
procedure TForm1.BrushColor1Change(Sender: TObject);
{ BrushColor1Change. }
const
BS: array [0 .. 7] of TBrushStyle = (bsSolid, bsClear, bsHorizontal,
bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross);
var
i: Integer;
hobj: Integer;
begin
BrushStyle1.ItemIndex := 0;
if BrushTransparency1.Position <> 255 then
DitheredColor1.Brush.Color := DitherColor(BrushColor1.Selected,
BrushTransparency1.Position)
else
DitheredColor1.Brush.Color := BrushColor1.Selected;
with ImageEnVect1 do
for i := 0 to SelObjectsCount - 1 do
begin
if i >= 0 then
begin
ObjSaveUndo;
hobj := SelObjects[i];
ObjBrushColor[hobj] := DitheredColor1.Brush.Color;
ObjLabelBrushColor[hobj] := DitheredColor1.Brush.Color;
ObjBrushStyle[hobj] := BS[BrushStyle1.ItemIndex];
ObjMemoCharsBrushStyle[hobj] := BS[BrushStyle1.ItemIndex];
end;
Update;
end;
UpdateGUI;
end;
To set the parameters of an object before it is created specify IEV_NEXT_INSERTED_OBJECT then set the objects parameters. In this case the object is created when dragged and dropped from a TButton:
procedure TForm1.ImageEnVect1DragDrop(Sender, Source: TObject; X, Y: Integer);
{ Drop object to mouse position from selected Drag & Drop buttons. }
var
i: Integer;
ihObj: Integer;
iNumberBoxes: Integer;
iNumberBitmaps: Integer;
begin
{ Accept drops from TButtons with Tags from 1 to 8 }
if (Source is TButton) and ((Source as TButton).Tag in [1 .. 8]) then
begin
AChanging := True;
PenStyle1.ItemIndex := 0;
iNumberBoxes := 1;
iNumberBitmaps := 1;
{ Specify the layer index where the object is located (drawn and referenced) }
ImageEnVect1.ObjLayer[IEV_NEXT_INSERTED_OBJECT] :=
ImageEnVect1.LayersCurrent;
ImageEnVect1.ObjText[IEV_NEXT_INSERTED_OBJECT] := 'Box';
ImageEnVect1.ObjFontLocked[IEV_NEXT_INSERTED_OBJECT] := False;
ImageEnVect1.ObjPenWidth[IEV_NEXT_INSERTED_OBJECT] :=
StrToIntDef(PenWidth1.Text, 1);
ImageEnVect1.ObjPenStyle[IEV_NEXT_INSERTED_OBJECT] := psSolid;
ImageEnVect1.ObjPenColor[IEV_NEXT_INSERTED_OBJECT] := PenColor1.Selected;
ImageEnVect1.ObjBrushStyle[IEV_NEXT_INSERTED_OBJECT] := bsSolid;
ImageEnVect1.ObjBrushColor[IEV_NEXT_INSERTED_OBJECT] :=
BrushColor1.Selected;
{ Make sure the object dimensions are less than the bitmap dimensions }
if ImageEnVect1.Bitmap.Width <= 64 then
begin
ImageEnVect1.ObjWidth[IEV_NEXT_INSERTED_OBJECT] :=
ImageEnVect1.Bitmap.Width div 2;
ImageEnVect1.ObjHeight[IEV_NEXT_INSERTED_OBJECT] :=
ImageEnVect1.Bitmap.Height div 2;
end
else
begin
ImageEnVect1.ObjWidth[IEV_NEXT_INSERTED_OBJECT] := 64;
ImageEnVect1.ObjHeight[IEV_NEXT_INSERTED_OBJECT] := 64;
end;
ihObj := ImageEnVect1.AddNewObject;
{ Count the number of object types }
for i := 0 to ImageEnVect1.ObjectsCount - 1 do
begin
if ImageEnVect1.ObjKind[i] = iekBOX then
Inc(iNumberBoxes);
if ImageEnVect1.ObjKind[i] = iekBITMAP then
Inc(iNumberBitmaps);
end;
ImageEnVect1.ObjLayer[ihObj] := ImageEnVect1.LayersCurrent;
case (Source as TButton).Tag of
1:
begin
ImageEnVect1.MouseInteractVt := [miPutBox];
ImageEnVect1.ObjKind[ihObj] := iekBOX;
ImageEnVect1.ObjName[ihObj] :=
AnsiString('Box ' + IntToStr(iNumberBoxes));
end;
2:
begin
ImageEnVect1.MouseInteractVt := [miPutBitmap];
ImageEnVect1.ObjKind[ihObj] := iekBITMAP;
ImageEnVect1.ObjBitmap[ihObj] := ImageEnView1.IEBitmap;
ImageEnVect1.ObjName[ihObj] :=
AnsiString('Bitmap ' + IntToStr(iNumberBitmaps));
ImageEnVect1.ObjWidth[ihObj] := ImageEnView1.IEBitmap.Width;
ImageEnVect1.ObjHeight[ihObj] := ImageEnView1.IEBitmap.Height;
{ Do not allow resizing bitmap objects }
ImageEnVect1.ObjStyle[ihObj] := ImageEnVect1.ObjStyle[ihObj] -
[ievsSizeable];
end;
end;
ImageEnVect1.ObjLeft[ihObj] := ImageEnVect1.Layers
[ImageEnVect1.LayersCurrent].ConvXScr2Bmp(X);
ImageEnVect1.ObjTop[ihObj] := ImageEnVect1.Layers
[ImageEnVect1.LayersCurrent].ConvYScr2Bmp(Y);
ImageEnVect1.MouseInteractVt := [miObjectSelect];
ImageEnVect1.AddSelObject(ihObj);
ImageEnVect1.UnSelAllObjects;
UpdateStatusbar;
end
else
begin
ImageEnVect1.MouseInteractVt := [miObjectSelect];
ImageEnVect1.UnSelAllObjects;
end;
AChanging := False;
end;
procedure TForm1.ImageEnVect1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
{ Accept drop objects from TButtons. }
begin
Accept := Source is TButton;
end;
William Miller Adirondack Software & Graphics Email: w2m@frontiernet.net EBook: http://www.imageen.com/ebook/ Apprehend: http://www.frontiernet.net/~w2m/index.html Custom Commercial ImageEn Development |
|
|
spetric
Croatia
308 Posts |
Posted - May 29 2014 : 12:14:33
|
Hi Bill,
I'll try to answer your questions:
How did you add the ellipse as shown in you post?
I have extracted only the line drawing and presented it in code. Here is how it looks when there is some kind of compound object (ellipse, line and text)
// mouse down event
// line with circle around it and text (line angle)
// _hobj, xDown and yDown as in previous post
PaintView->ObjKind[_hobj] = iekLINE;
PaintView->ObjBrushStyle[_hobj] = bsSolid;
PaintView->ObjBrushColor[_hobj] = clBlue;
PaintView->ObjEndShape[_hobj] = iesOUTARROW;
// new objects (circle + text)
_hAdd1 = PaintView->AddNewObject();
PaintView->ObjKind[_hAdd1] = iekELLIPSE;
PaintView->ObjPenStyle[_hAdd1] = psDot;
PaintView->ObjTop[_hAdd1] = yDown;
PaintView->ObjLeft[_hAdd1] = xDown;
PaintView->ObjWidth[_hAdd1] = 0;
PaintView->ObjHeight[_hAdd1] = 0;
PaintView->ObjPenWidth[_hAdd1] = someWidth;
PaintView->ObjPenColor[_hAdd1] = someColor;
PaintView->ObjStyle[_hAdd1] = TIEVStyle()<<ievsVisible;
//
_hAdd2 = PaintView->AddNewObject();
PaintView->ObjKind[_hAdd2] = iekTEXT;
PaintView->ObjFontHeight[_hAdd2] = -15;
PaintView->ObjFontName[_hAdd2] = "Tahoma";
PaintView->ObjText[_hAdd2] = "";
PaintView->ObjTextAlign[_hAdd2] = iejCenter;
PaintView->ObjPenStyle[_hAdd2] = psClear;
PaintView->ObjTop[_hAdd2] = yDown;
PaintView->ObjLeft[_hAdd2] = xDown;
PaintView->ObjWidth[_hAdd2] = 40;
PaintView->ObjHeight[_hAdd2] = 30;
Mouse move:
// mouse move event
// xMove and yMove as in previuso post
double radius, angle;
PaintView->ObjWidth[_hobj] = xMove - PaintView->ObjLeft[_hobj];
PaintView->ObjHeight[_hobj] = yMove - PaintView->ObjTop[_hobj];
// following function returns angle and radius length
pxaf_GetLineData(&radius, &angle, xDown, _yDown, xMove, yMove);
PaintView->ObjLeft[_hAdd1] = xDown - fast_ftol(radius);
PaintView->ObjTop[_hAdd1] = yDown - fast_ftol(radius);
PaintView->ObjWidth[_hAdd1] = fast_ftol(radius)*2;
PaintView->ObjHeight[_hAdd1]= fast_ftol(radius)*2;
// angle with decimals -> PaintView->ObjText[_hAdd2] = FloatToStr(180.0 * angle/M_PI);
// angle as integer (I don't need decimals)
PaintView->ObjText[_hAdd2] = IntToStr(fast_ftol(180.0 * angle/M_PI));
Note: fast_ftol is small assembly routine that converts double to integer. I think we don't need this with XE5, however it works faster with BCB6, especially in loop with large ammount of data (pixels).
pxaf_GetLineData is a simple procedure that calculates angle and radius of a line drawn from x1,y1 to x2,y2. If someone need this I can post it.
How did you turn off the drawing by setting ImageEnVect1.MouseInteractVt <> [miObjectSelect])?
Well, I'm actually deleting object (after rendering) in OnMouseUp and use data of an object (angle, radius) to perform some rendering (int this case it's image warping). However, if you want to leave object on ImageEnVect, in OnMouseUp event simply set ImageEnVect->OnMouseMove = 0;
So, initially, OnMouseMove event is set to 0. In OnMouseDown event set ImageEnVect->OnMOuseMove = MouseMove; and then in OnMouseUp event again set OnMouseMOve to 0.
Obviously, when you want to manipulate vectorial object in usual way (select, move, size) OnMouseDown event must be set to 0 (NULL). To add a new object, again set OnMOuseMoveDown object to method MouseDown.
|
|
|
w2m
USA
1990 Posts |
Posted - May 29 2014 : 12:33:44
|
Thanks for the info Spetric.
William Miller |
|
|
spetric
Croatia
308 Posts |
Posted - May 29 2014 : 12:37:26
|
In OnMouseMove event, on some objects, I'm checking TShiftState and if Shift key is pressed I'm moving object around (translation). When Alt key is pressed I'm drawing circle/square instead of ellipse/rectangle and when Ctrl key is pressed I'm rotating the object.
This Ctrl "option" comes handy, when you want to rotate rectangle/square:
Now, you can't do it with iekBOX object, but I use the trick: instead of iekBOX I'm using closed iekPOLYLINE with 4 points...and so constructed rectangle can be rotated. The same thing can be done with ellipse, but I did not implemented as it's more complicated...to much points :) |
|
|
spetric
Croatia
308 Posts |
Posted - May 29 2014 : 12:46:12
|
Here you can see those compound objects in action:
http://www.youtube.com/watch?v=1H6-ssIPX-4
Please, ignore my accent in this video, it sound like Will Sasso's impression of Arnold Schwarzenegger. |
|
|
xequte
38514 Posts |
Posted - May 29 2014 : 20:27:48
|
Wow, Spetric, really enjoyed your video (your accent is way better than mine, and English is my first language ). Those are some awesome effects!
Nigel Xequte Software www.xequte.com nigel@xequte.com
|
|
|
|
Topic |
|
|
|