By drawing layer I mean a layer where the user can manually draw lines, circles or other shapes. And by normal layers I mean the layers described in the graphics32 layers example (the layers that can be moved or resized at runtime using mouse events) So I am having difficulties combining these 2 types of layers. In my test project, for now, I will assume I only have one drawing layer and multiple PNG layers. So in my project I set properties for the ImgView32 in the OnFormCreate like:
procedure TForm1.FormCreate(Sender: TObject);
begin
AWidth:= 800;
AHeight:= 600;
FillColor:=clWhite;
with ImgView do
begin
Selection := nil;
RBLayer := nil;
Layers.Clear;
Scale := 1;
Scaled:=true;
Bitmap.SetSize(AWidth, AHeight);
Bitmap.DrawMode := dmTransparent;
Bitmap.Clear(FillColor);
end;
end;
After this, onClick of a button, I add a number of layers (containing transparent PNG images). So it's like this
procedure TForm1.Button1Click(Sender: TObject);
begin
AddPNGLayer(1);
AddPNGLayer(2);
AddDrawingLayer;
AddPNGLayer(3);
end;
(I wont elaborate here the adding of PNG layers in order to keep the question short. I will only say that it uses a different onMouseDown event (layerMouseDown) than the one used in the drawingLayer) and the AddDrawingLayer is as follows:
procedure TForm1.AddDrawingLayer;
var
P:TPoint;
jumaH, JumaW, W, H: Single;
begin
imwidth := ImgView.Bitmap.Width;
imheight := ImgView.Bitmap.Height;
xofx := (ImgView.ClientWidth - 17 - imwidth) div 2; // substracting the width of the scrollbar
yofy := (ImgView.ClientHeight - 17 - imheight) div 2; // same here with height
bm32 := TBitmap32.Create;
bm32.DrawMode := dmTransparent;
bm32.SetSize(ImgView.Bitmap.Width,ImgView.Bitmap.Height);
bm32.Canvas.Pen.Width := 3;
bm32.Canvas.Pen.Color := clBlack32;//pencolor;
BB := TBitmapLayer.Create(ImgView.Layers);
try
BB.Bitmap.DrawMode := dmTransparent;
BB.Bitmap.SetSize(imwidth,imheight);
BB.Bitmap.Canvas.Pen.Width := 3;
BB.Bitmap.Canvas.Pen.Color := pencolor;
BB.Location := GR32.FloatRect(0, 0, imwidth, imheight);
BB.Scaled := true;
BB.Tag:=3;
//// Selection:=BB; // if I use this then I cant draw because the entire layer is selected and the mouseDown event works as a mover/resizer
// BB.OnMouseDown := DrLayerMouseDown;
// BB.OnMouseUp := DrLayerMouseUp;
// BB.OnMouseMove := DrLayerMouseMove;
// BB.OnPaint := DrLayerOnPaint;
RBLayer:=nil;
EdLayerIndex.Text:=IntToStr(BB.Index);
finally
BB.Free;
end;
FDrawingLine := false;
// swapBuffers32; // needed when mouse events are active
end;
EdLayerIndex is a EditBox where I display the created/selected Layer index (for debugging)
- As you can see above, if I keep
Selection:=BB
andRBLayer:=nil
then the drawingLayer is only movable and resizable, so it's not a good solution since I want to use my Mouse events in this particular layer to draw. If I comment only the
RBLayer:=nil
while keepingSelection:=BB
then the drawingLayer is not movable anymore, but I cannot select other layers that are under the drawingLayer. I can only access the top layer (the last added PNG layer)If I comment the
Selection:=BB
then I cannot select other layers with my mouse. So in my case I declared 2 png layers before my drawingLayer and one after it. On runtime I can only select the last layer (the one 'above' the drawingLayer) So this is not a solution either.
How can I do it that when I click on the drawing layer (or select it otherwise, like in a listbox or something), the drawingLayer wont be movable, but my drawing Mouse Events will kick in? And all this while I can go away from the drawingLayer whenever I want and select other layers to move around and play with. So basically I need a particular layer to NOT act like the other layers.
What I want to achieve is having a classic Photoshop-like or paint.net like behavior using graphics32. And it is very confusing how these layer properties actually work.
So far I figured out how to draw (lines, circles, rectangles) on a transparent layer dynamically (using mouse events). So I can have a drawing layer. The drawing happens in my DrLayerMouseDown
, DrLayerMouseUp
, DrLayerMouseMove
, DrLayerPaint
events. But I cannot seem to understand how to combine such a drawing layer with regular movable/resizable layers.
The rest of the code (like setSelection
, RBResizing
and layerMouseDown
) is mostly taken from the layers example of the graphics32 library.
EDIT
In order to test your idea with layerOptions
, I did the following:
1.Started a new test project with an ImgView on it, and a button
2.On create i used the same code as before
3.OnButtonClick I added ONE layer using a modified AddDrawingLayer like this:
...
BB.Scaled := true;
Selection:=BB;
Selection.LayerOptions:=Selection.LayerOptions and (not LOB_MOUSE_EVENTS); // I also tried it with BB instead of Selection
BB.OnMouseDown := DrLayerMouseDown;
BB.OnMouseUp := DrLayerMouseUp;
BB.OnMouseMove := DrLayerMouseMove;
BB.OnPaint := DrLayerOnPaint;
...
expecting it to become insensitive to Mouse Events. But the layer is still movable instead of being insensitive to mouse. So it's like I did not do anything
So I do not think it helps me using this option unless I am doing it wrong So onCreate of the layer, this option does not seem to stick. But if I disable mouse events for all layers, one-by-one like in the next EDIT, then the drawing layer gets disabled (mouse events)
EDIT
Also I tried another test project, same idea: same onCreate, and onButtonClick I add 3 layers (using the Layers example of the library) containing an image each (no drawing layer this time, to keep it simple). Then I added a new button where if you click it, the next code is executed:
for i := 0 to ImgView.Layers.Count-1 do
(ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions:= (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions and (not LOB_MOUSE_EVENTS);
My purpose was to make all layers insensitive to mouse events. I succeeded, after clicking the new button, the layers could not be selected anymore, however when I wanted to re-enable mouse events for the layers (adding a third button with the next code onClick):
for i := 0 to ImgView.Layers.Count-1 do
(ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions:= (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions and (LOB_MOUSE_EVENTS);
No error was shown, but when I tried to select a layer in order to move it ... all the images of the layers disappeared from the view... leaving me with a white background empty ImgView.
What am I doing wrong? In order to do what you suggested with LayerOptions, I need to be able to disable mouse events for all layers, and enable mouse events for a specific layer, and then when editing is done, I need to be able to re-enable mouse events for all layers, but I am doing it wrong I guess.