EditorFactory - Module for object management in a Canvas

Share your advanced PureBasic knowledge/code with the community.
punak
User
User
Posts: 81
Joined: Tue Sep 07, 2021 12:08 pm

Re: EditorFactory - Module for object management in a Canvas

Post by punak »

ShadowStorm wrote: Wed May 17, 2023 12:09 pm Hello punak,
Yes but basically this module is not for creating "Gadgets" but "Manipulatable graphic objects", and I don't understand why you want a separator, what is the purpose here?
the designer I want to build with your engine needs splitter graphic object. I have no quarrel over words. :) this is a feature, now let's call it Gadget or graphic object.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Look, show us exactly what you want, but if I understand correctly, for each object you want to be able to put a separator on it, to divide it in 2 vertically or horizontally I guess, is that right?
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
The Gost
User
User
Posts: 11
Joined: Fri Jan 03, 2025 5:35 pm

Re: EditorFactory - Module for object management in a Canvas

Post by The Gost »

Greetings, :)

I just discovered this very interesting module, and I have a few questions.

If I understood correctly, it is no longer maintained, which is a shame. :(
It’s true that, at first glance, one might wonder what it could be used for, but with a bit of imagination, there are many things that could be done with it.

In fact, I was thinking about a small program for creating/editing graphics that I would have liked to develop using this module.
I would have liked to be able to draw directly with my mouse inside the objects, but I have no idea how to do that.

In my program, I want to create objects that would essentially act like image containers. Each object would have its own graphics, but I want to be able to draw inside these objects with the mouse. For example, drawing points, lines, squares or rectangles, triangles, etc.—many shapes. But all of this with the mouse: I would select a shape to draw, then draw it inside the object wherever I want. I’m not sure if I’m being clear.

It’s a bit like if each object were a canvas, but not quite a real one. :)

there's this example in the PureBasic help, I have no idea how to do that in my Objects with this module ?:

Code: Select all

If OpenWindow(0, 0, 0, 220, 220, "Canvas container", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  CanvasGadget(0, 10, 10, 200, 200, #PB_Canvas_Container)
  ButtonGadget(1, 10, 10, 80, 30, "Effacer")
  CloseGadgetList()
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget
      Select EventGadget() 
        Case 0
          If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(0, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
            If StartDrawing(CanvasOutput(0))
              x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
              y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              Circle(x, y, 10, RGB(Random(255), Random(255), Random(255)))
              StopDrawing()
            EndIf
          EndIf
          
        Case 1
          If StartDrawing(CanvasOutput(0))
            Box(0, 0, 200, 200, #White)
            StopDrawing()
          EndIf
      EndSelect
    EndIf
    
  Until Event = #PB_Event_CloseWindow
EndIf
ah and there are a few things I'd be interested in too:

Knowing when the mouse moves on an Object, currently there's no “Move” event, is there ?
There's no way of knowing where the mouse is on my Object with this module either, is there ?

My project isn't going to be easy to do, but with this module, things will be much easier than without it!
Thanks again :D
The Gost
User
User
Posts: 11
Joined: Fri Jan 03, 2025 5:35 pm

Re: EditorFactory - Module for object management in a Canvas

Post by The Gost »

Hi, there,

Nobody to answer me?
If Stargate could answer me because he's the one who coded it.

Maybe something should be added to the module.
to be able to do this kind of thing?

I don't know how to do what I want, I can't find it.
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: EditorFactory - Module for object management in a Canvas

Post by STARGÅTE »

Dear The Gost, welcome to our forum.
The Gost wrote: Sat Jan 04, 2025 11:25 pm Knowing when the mouse moves on an Object, currently there's no “Move” event, is there ?
There's no way of knowing where the mouse is on my Object with this module either, is there ?
PureBasic has its own event for mouse movement:
When the mouse is moved in the CanvasGadget, EventType() returns #PB_EventType_MouseMove.
To check whether the mouse has entered an object you can use the CanvasObjectsEvent() function (which gives the event #Event_Object) and then CanvasObjectsEventType() to check regarding #EventType_MouseEnter. EventObject() gives then the object number in which the mouse has entered.
When you want to check a specific object, if it's hovered by the cursor, you can use: ObjectState(). It will return the flag: #State_Hovered which you can check with "If ObjectState(Object) & #State_Hovered".
The Gost wrote: Sat Jan 04, 2025 11:25 pm It’s a bit like if each object were a canvas, but not quite a real one. :)
there's this example in the PureBasic help, I have no idea how to do that in my Objects with this module ?:
As it is written in the PureBasic documentation, you can check the mouse position on the canvas with GetGadgetAttribute(0, #PB_Canvas_Mouse[X|Y]). For the object, you know its position with GetObject[X|Y].
With both you can calculate the mouse position inside the object. When you want to "draw" on objects, each object need an own image (which you can store for the object, e.g. SetObjectData()).
Then you can perform the same drawing (like in the Pure Basic documentation) on this image and draw the image within the drawing callback "SetObjectDrawingCallback()" of the object, like it is done in Example06_Gadgets.pb of the module.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Hello everyone,

I wanted to let you know that I haven’t abandoned Editors Factory (EF) and that I’m still working on it, mainly to create examples and demos, as well as to bring some order to the project.

I have already made good progress and have created some nice examples and demos.

To respond to what The Gost said, it’s true that at first glance, one might wonder what this module is for.

If it’s just about "playing" in a canvas with objects, that’s fine, but what’s the point, other than manipulating our objects as we wish, knowing everything that’s happening on them, and acting accordingly? Just that, I think, is already quite significant, don’t you?

That said, there’s still work to be done to make interesting things with this module. It already handles a large part of the necessary work for manipulating and managing object events, with many customizable elements.

But I admit that one might reasonably question the usefulness of such a module. I remain optimistic, however, because with a bit of imagination, you can do some really nice things, like visual designers. Of course, this type of project still requires a lot of work because EF only does part of the job.

At first, I had certain expectations regarding what could be done with this module. For example, it wasn’t designed to allow the full creation of gadgets, but you can still make them yourself.

EF was mainly intended to manipulate virtual objects in a canvas. It’s possible that the chosen name isn’t the most appropriate, at least not in its current state!

There are still features that I would have liked to add to this module, but unfortunately, I don’t have the skills to do so, and it bothers me a lot.

Stargate has already done a lot for this project, and I understand that for him, it’s over. If I understand correctly, he doesn’t want to hear about it anymore.

I haven’t found anyone else to take over the project.
The license is a problem for some, and I’m personally against the idea of a free commercial license for now. Maybe one day, after my death—who knows...

If you don’t hear from me for several years, for example 5 years (including on the French forum), then EF could eventually move to a free license, even a commercial one.

Anyway.

For your requests, The Gost, and welcome as well, in the current state, objects are drawn by a drawing procedure every time there are changes to them, for example, if you move or resize them.

But what you’re asking for is special; the procedure would need to account for every new change in the image you want, which is a real headache!

Yes, currently, you can’t do what the code in the PureBasic help shows. It’s not impossible with some work, but it remains complicated to do.

The drawing procedure currently takes into account: Width.i, Height.i, iData.i. So the drawing can adapt to the size of the object, as you can see in the examples where the drawing is updated each time the object’s size changes.

To do what you want, you would, I imagine, need to take the initial image, add your graphics to it (a colored circle in your example), then give this image back to the drawing procedure, which will redraw it every time you make a change.

It’s a very interesting request, I’ll look into it and see what kind of example I can come up with for this specific case, which remains very interesting and original!

Maybe Stargate could give his opinion, if he has ideas on the matter, if it would be possible to add something, like a sort of parameter to the drawing procedure to handle this. I really don’t know how we could do that.

"Knowing when the mouse moves over an object, currently there is no 'Move' event, is there?
There’s no way to know where the mouse is on my object with this module either, is there?"

Indeed, there’s no function to do this at the moment, but you can do it as mentioned in a previous message; you have to compare the mouse position on the canvas with the object, something like that.

There are things I would also have liked to add myself, for example:

SetObjectBoundaryStyle() does not work, it is not used. Would it be possible to implement it, please?

AttachObject(), I would like to be able to modify the “eMode” of objects, to change the attachment method. Currently, the child object is attached to the X, Y of the parent object. I would like to add other modes, why not “Width” and “Height”. For now, the child object changes position if the X and/or Y position of the parent object changes. I would like to do more things, for example: attach objects to an object to create window buttons. (Maybe X and Y + Width of the parent object?)

We could also have other modes, like: X + Y + Height, or X + Y + Height + Width.

ExamineObjects(), I don’t think it takes into account loaded objects, is that correct? It would be nice if the function updated itself when objects are loaded. (Currently, it updates on creation and deletion, is that correct?)

Other ideas in passing, notably your request about the mouse position on objects:

ObjectMouseX()
ObjectMouseY()
BindObjectEvent()
UnBindObjectEvent()
New events for "attach" and "detach" objects: when an object is attached to or detached from another.

And something another person wanted—a Splitter?

There are still other things I wanted to add to this module, like object rotation, among other things, and also the ability to make objects that can be linked with lines, for example, to create flowcharts, and other things.

It’s very frustrating to have projects and not be able to make them happen.
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
The Gost
User
User
Posts: 11
Joined: Fri Jan 03, 2025 5:35 pm

Re: EditorFactory - Module for object management in a Canvas

Post by The Gost »

Hello and thank you for your welcome Stargate and ShadowStorm :D
STARGÅTE wrote: Wed Jan 08, 2025 9:36 pm When you want to "draw" on objects, each object need an own image (which you can store for the object, e.g. SetObjectData()).
Does the module have anything for finding out the image of an object? how am I supposed to do something like that ?
Stargate, could you please show me how it's done ?

ShadowStorm, what a pavement you've made here :D
There's a lot to say, but I'll see as I go along, I don't have much time right now. In any case, thank you for your message.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

The Gost wrote: Thu Jan 09, 2025 8:26 pm Hello and thank you for your welcome Stargate and ShadowStorm :D
STARGÅTE wrote: Wed Jan 08, 2025 9:36 pm When you want to "draw" on objects, each object need an own image (which you can store for the object, e.g. SetObjectData()).
Does the module have anything for finding out the image of an object? how am I supposed to do something like that ?
Stargate, could you please show me how it's done ?

ShadowStorm, what a pavement you've made here :D
There's a lot to say, but I'll see as I go along, I don't have much time right now. In any case, thank you for your message.
Um, it's true that it could be a good idea to have a function to return the image of an Object, but after it's been drawn by its drawing procedure I imagine, I think it's a good idea, we could set that up, do you think Stargate? yes, because I don't see how I could do that, so I think it's a good idea, do you agree with me ?

GetObjectImage() ? or GetObjectDrawing() (I think that's pretty good, don't you?)

You're welcome The Gost and good luck and if you need any help don't hesitate.
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

The Gost, We can use the canvas by doing a GrabImage(), you know the position of your object and its size, so it’s easy.

But then, maybe you want the image exactly as it is displayed on the object, and that’s different... because the canvas has a white background, and your object’s image might have fully transparent parts.

I’m thinking about all this to see what I can do while waiting for Stargate to have time to respond when he’s ready.

Personally, I also have some issues on my side. When an object is resized using the handles (mouse button released), you have to move the mouse out of the object for the drawing procedure to update it one last time (when the mouse enters and exits the object, it’s currently updated).
Another topic about this is discussed below ***

We could maybe add a function to force the drawing procedure to be called, but we can already use SetObjectDrawingCallback() to update it, and it’s true that it works. However, there’s an issue: you need to recall it with the same parameters if you want to keep, for example, the object’s data.

Code: Select all

Runtime Procedure MyDrawingObject(Object.i, Width.i, Height.i, iData.i)

; Basic graphic. 
AddPathBox(0.5, 0.5, Width - 1, Height - 1)
VectorSourceColor(RGBA(255, 255, 255, 255))
FillPath()

AddPathBox(0.5, 0.5, Width - 1, Height - 1)
VectorSourceColor(iData | $80000000)
FillPath(#PB_Path_Preserve)
VectorSourceColor(iData | $FF000000)
StrokePath(1)

EndProcedure
In this example, iData contains a color, so if you recall the function, you’ll have to provide the same color to avoid changing the object’s colors.

So, you’ll need to store the object’s color, for example, using a SetObjectDictionary() or SetObjectData(), then recall these values and pass them to the object’s drawing procedure. If you do that, it works, but honestly, I would really prefer something simpler, like a RefreshObjectDrawingCallback(Object), which would force the procedure to redraw the object with its current values. I don’t know if I’m being clear, but oh well.

*** I looked at the example of the gadgets mentioned by Stargate, OK, it handles the mouse with an ObjectStat and states, which is fine, but anyway, we’re going to have a big problem here if you want to draw with the mouse on an object. Nothing can be done here because the object’s image is only updated if the mouse enters or exits the object, or if it’s moved or resized, but nothing happens while the mouse is inside, like this famous "Move". So all this complicates the situation!
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: EditorFactory - Module for object management in a Canvas

Post by STARGÅTE »

The Gost wrote: Thu Jan 09, 2025 8:26 pm Does the module have anything for finding out the image of an object? how am I supposed to do something like that ?
Stargate, could you please show me how it's done ?
No, because the objects have no own image by default. It would be inefficient to first draw the object on an image and then draw this image again on the canvas, if you instead draw the object directly on the canvas.

If you still need your own image as a drawing surface, create it yourself, here is an example:
You can draw on both objects or (when the toggle button is pressed) you can move and resize both objects.

Code: Select all

XIncludeFile "EditorFactory.pbi"
UseModule EditorFactory

Enumeration 1
	#Window
	#Gadget_Canvas
	#Gadget_Toggle
EndEnumeration

Enumeration 1
	#Object1
	#Object2
EndEnumeration

; Custon drawing callback to draw the object with the image
Runtime Procedure MyDrawing(Object.i, Width.i, Height.i, iData.i)
	MovePathCursor(0, 0)
	DrawVectorImage(ImageID(GetObjectData(Object))) ; The image is stored in object data.
	AddPathBox(0.5, 0.5, Width-1, Height-1)
	VectorSourceColor($80000000)
	StrokePath(1)
EndProcedure

OpenWindow(#Window, 0, 0, 800, 450, "Draw on objects", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget_Canvas, 0, 30, WindowWidth(#Window), WindowHeight(#Window)-30, #PB_Canvas_Keyboard)
ButtonGadget(#Gadget_Toggle, 0, 0, 800, 30, "Paint on objects (off) or move/resize objects (on/pushed)", #PB_Button_Toggle)

InitializeCanvasObjects(#Gadget_Canvas, #Window)
SetCursorSelectionStyle(#Gadget_Canvas, #SelectionStyle_Solid) 

; Create two objects with painting images and drawing callbacks:
CreateObject(#Gadget_Canvas, #Object1, 20, 20, 200, 100)
CreateObject(#Gadget_Canvas, #Object2, 320, 20, 200, 100)
SetObjectData(#Object1, CreateImage(#PB_Any, 200, 100, 32, #PB_Image_Transparent))
SetObjectData(#Object2, CreateImage(#PB_Any, 200, 100, 32, #PB_Image_Transparent))
SetObjectDrawingCallback(#Object1, "MyDrawing()")
SetObjectDrawingCallback(#Object2, "MyDrawing()")

Repeat
	
	Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			Break
		Case #PB_Event_Gadget
			Select EventGadget()
				Case #Gadget_Canvas
					Select EventType()
						Case #PB_EventType_MouseMove
							; Draw on the images of the object when Toggle botton is of, mouse was mouved and pusehd.
							If Not GetGadgetState(#Gadget_Toggle) And ExamineObjects(#Gadget_Canvas)
								Object = NextObject(#Gadget_Canvas)
								While Object
									If ObjectState(Object) & #State_LeftMousePushed
										If StartDrawing(ImageOutput(GetObjectData(Object))) ; Start drawing ob the object image stored in object data.
											DrawingMode(#PB_2DDrawing_AlphaBlend)
											X = GetGadgetAttribute(#Gadget_Canvas, #PB_Canvas_MouseX) - GetObjectX(Object) ; Local position
											Y = GetGadgetAttribute(#Gadget_Canvas, #PB_Canvas_MouseY) - GetObjectY(Object) ; Local position
											Circle(X, Y, 2, RGBA(0, 64, 255, 255))
											StopDrawing()
										EndIf
										ShowObject(Object) ; Trigger a repaint on the canvas gadget.
									EndIf
									Object = NextObject(#Gadget_Canvas)
								Wend
							EndIf
					EndSelect
				Case #Gadget_Toggle ; Painting or object handels
					If GetGadgetState(#Gadget_Toggle)
						AddObjectHandle(#Object1, #Handle_Size | #Handle_Position)
						AddObjectHandle(#Object2, #Handle_Size | #Handle_Position)
					Else
						RemoveObjectHandle(#Object1, #Handle_Size | #Handle_Position)
						RemoveObjectHandle(#Object2, #Handle_Size | #Handle_Position)
					EndIf
			EndSelect
	EndSelect
	
	; Event loop for the objects in the canvas gadget
	Repeat
		Select CanvasObjectsEvent(#Gadget_Canvas)
			Case #Event_Object
				Select CanvasObjectsEventType(#Gadget_Canvas)
					Case #EventType_Resized ; The object was resized, so the image have to be resize as well
						Object = EventObject(#Gadget_Canvas)
						SetObjectData(Object, GrabImage(GetObjectData(Object), #PB_Any, 0, 0, GetObjectWidth(Object), GetObjectHeight(Object)))
				EndSelect
			Case #Event_None
				Break
		EndSelect
	ForEver

ForEver

End
EDIT: Updated for 1.18
ShadowStorm wrote: Wed Jan 08, 2025 10:13 pm SetObjectBoundaryStyle() does not work, it is not used. Would it be possible to implement it, please?
No. It was planed to show the boundary lines when on object was limited by SetObjectBoundaries(). However, it worked not well, so I removed it.
ShadowStorm wrote: Wed Jan 08, 2025 10:13 pm AttachObject(), I would like to be able to modify the “eMode” of objects, to change the attachment method. Currently, the child object is attached to the X, Y of the parent object. I would like to add other modes, why not “Width” and “Height”. For now, the child object changes position if the X and/or Y position of the parent object changes. I would like to do more things, for example: attach objects to an object to create window buttons. (Maybe X and Y + Width of the parent object?)
We could also have other modes, like: X + Y + Height, or X + Y + Height + Width.
I didn't understand. What do you mean with " other modes, why not Width and Height"? Attaching the width of the child to the width of the parent when resizing the parent? Or do you mean, attaching the X position of the child to the (X+Width)-position of the parent?
ShadowStorm wrote: Wed Jan 08, 2025 10:13 pm ExamineObjects(), I don’t think it takes into account loaded objects, is that correct? It would be nice if the function updated itself when objects are loaded. (Currently, it updates on creation and deletion, is that correct?)
Examine Objects() lists all object, which a in the canvas gadget, either created or loaded, doesn't matter.
ShadowStorm wrote: Wed Jan 08, 2025 10:13 pm There are still other things I wanted to add to this module, like object rotation, among other things, and also the ability to make objects that can be linked with lines, for example, to create flowcharts, and other things.
In general:
Expressing feature requests and wishes is of cause welcomed. However, it is up to the programmer to decide if a feature is easy to implement or impossible. ObjectMouseX() is of course easy to implement, it's one line of code. Object rotation is impossible, because the module, drawing and event pipeline was not designed for such thinks and have to re-coded from scratch.
However, at the moment I have no time and no desire (I admit this openly) to work on this module. I just can give small support (help or bug fixes) of the published version, which I did in the previous posts.
Last edited by STARGÅTE on Fri Jan 24, 2025 9:47 am, edited 1 time in total.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Hi Stargate,
I didn't understand. What do you mean with " other modes, why not Width and Height"? Attaching the width of the child to the width of the parent when resizing the parent? Or do you mean, attaching the X position of the child to the (X+Width)-position of the parent?
Not easy to explain...

I want the attached object to be able to react in different ways depending on the object it's attached to.

Currently there are X and Y, that's all, I need other things.
Here are various additional examples (I'm not sure of myself):

The attached object changes its width based on the object it is attached to (Proportionally). #Attachment_Width

OR

The attached object changes its height based on the object it is attached to (Proportionally). #Attachment_Height

OR

Both at the same time. #Attachment_Width + #Attachment_Height

Be careful, these new modes can also be used with #Attachment_X (and/or) #Attachment_Y if desired.

I can very well change, for example, only the width or the height or both of the attached object without changing its position
because currently, it is perfectly possible to change the position of the attached object on: X or Y or both!

I also need:

The attached object changes its X position based on the object it is attached to (Proportionally). #Attachment_X2

OR

The attached object changes its Y position based on the object it is attached to (Proportionally). #Attachment_Y2

OR

Both at the same time. #Attachment_X2 + #Attachment_Y2

Be careful, these new modes can also be used with #Attachment_X (and/or) #Attachment_Y, #Attachment_Width, #Attachment_Height if desired.

All these modes can therefore be combined together to make something customizable.

For example, to make a window, you need buttons (at the top right), they must change their position based on the X and Y position of the window but also based on the width of the window to adapt to it. Here, I call this #Attachment_X + #Attachment_X2 (the buttons do not change size, just their position based on the width of the window.)

But the buttons could very well be at the bottom right, or at the bottom left, or in the center!

I don't think it's very clear, so I imagine that pictures would be better ^^.
the examples in the images are very approximate.

https://drive.google.com/file/d/14S3Tjh ... sp=sharing

I don't know if I'm making myself clear yet ^^
It's complicated.
Examine Objects() lists all object, which a in the canvas gadget, either created or loaded, doesn't matter.
you say that in the file though: > ExamineObjects() so erweitern, dass man über gerade geladene Objekte iterieren kann.
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Oh, say, Stargate, didn't you tell me you were hiding secret stuff in your boot ?
what's this weird thing you've done with ShowObject() in your example here, it's not right ! :mrgreen:

So, ShowObject() is used to update the Object image, eh ? :?
Little sneak ! :lol:
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Hi everyone,

I spent several days creating this example based on a request from "The Gost". It was quite difficult to make, I must admit, a real headache, but it works as expected.

With this example, "The Gost", you’ll be able to draw on your objects with the mouse, selecting different drawing modes using the buttons on the window (1, 2, 3).

Double-click on an object to draw inside it.
This example is in French, but anyone can try it and see how it works.

I think there might be an easier way to do this, but I haven’t found another solution.

Stargate’s example is great too, thanks to him !

Version of this code for: Editors Factory.pbi 1.19

Code: Select all

; Dessiner sur des objets avec diverses modes à l'aide d'un canevas temporaire.
; Dans cet exemple assez compliqué, nous allons pouvoir dessiner sur nos objets à l'aide d'un canevas temporaire.
; Double-cliquez sur un objet pour faire apparaître un canevas temporaire, dessinez-y avec le mode voulu, puis cliquez en dehors pour valider le dessin.

; Drawing on objects With various modes using a temporary canvas.
; In this rather complicated example, we're going to draw on our objects using a temporary canvas.
; Double-click on an object To bring up a temporary canvas, draw on it With the desired mode, then click outside To validate the drawing.
  
; Créé le: 12/01/2025 par Dieppedalle David Alias Shadow.
; Created on: 12/01/2025 by Dieppedalle David Alias Shadow.

; Inclue le fichier du programme.
XIncludeFile "Editors Factory.pbi"

; Initialise le module pour pouvoir l'utiliser.
UseModule EditorFactory

; ---------------------------------------------- Exemple: ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

; Constantes du programme.
Enumeration 100
  #Window  ; La Fenêtre.
  #Canevas ; Le Canevas.
  #CanevasTemporaire ; Canevas temporaire qui servira à déssiner sur un Objets.
  #BoutonDessinMode1 ; Bouton gadget pour le mode de déssin rond.
  #BoutonDessinMode2 ; Bouton gadget pour le mode de déssin carré plein.
  #BoutonDessinMode3 ; Bouton gadget pour le mode de déssin carré vide avec bordure.
  #ImageCanevasTemporaire ; Image temporaire ou on va déssiner dessus.
EndEnumeration

; La numérotation des Objets commence à partir de 1 jusqu'à 65535.
Enumeration 1
  #Objet1 ; Objet n°1.
  #Objet2 ; Objet n°2.
  #Objet3 ; Objet n°3.
  #Objet4 ; Objet n°4.
EndEnumeration

; Numérotation des Images additionnel des Objets.
Enumeration 1
  #ImageObjet1 ; Images Objet n°1.
  #ImageObjet2 ; Images Objet n°2.
  #ImageObjet3 ; Images Objet n°3.
  #ImageObjet4 ; Images Objet n°4.
EndEnumeration

; Variable Global.

; Variable qui sert à savoir si le Canevas est actif ou non, si on est en train de déssiner sur un Objets.
Global CanevasTemporaireActif.b = #False

; Le numéro de l'Objet en train d'être déssiné.
Global ActiveObject.i = 0

; Le numéro du canevas ou s'est passé un évènement.
Global Canevas.i = 0

; The drawing mode applied when drawing on an object.
; - Mode 1: draws randomly coloured circles;
; - Mode 2: draws a solid square, randomly colored;
; - Mode 3: draws an empty square with random-colored borders.

; Le mode de dessin appliqué quand on dessine sur un objet.
; - Mode 1: dessine des ronds de couleur aléatoire;
; - Mode 2: dessine un carré plein, de couleur aléatoire ;
; - Mode 3: dessine un carré vide avec des bordures de couleur aléatoire.
Global ModeDessin.i = 1

; Transparency of desined shapes.
; Transparence des Formes déssiné.
Global TransparenceRondPleins.i = 100
Global TransparenceCarrePleins.i = 125
Global TransparenceBordureCarreVide.i = 75

; Mémorise la position de la souris quand un clique gauche a lieu avec la souris l'or d'un mode de déssin > 1
Global MouseClickX.i
Global MouseClickY.i

; Mémorise la position de la souris quand elle se déplace sur le Canevas.
Global MouseMoveX.i
Global MouseMoveY.i

; Si l'Objets contient une image valide dans ses données, alors la retourne, sinon retourne 0.
Procedure.i IsObjectImage(Object.i)
  
  ; Si l'Objets a une image Additionnelle stoquer en tans que valeur Data.
  ObjectData.i = GetObjectData(Object.i)
  
  If ObjectData.i <> 0 And IsImage(ObjectData.i)
    ProcedureReturn GetObjectData(Object.i)
    
  Else
    ProcedureReturn 0
    
  EndIf
  
EndProcedure

; Quand un Objet est double cliqué.
Procedure WhenDoubleClickedObject()
  
  ; Activer le canevas temporaire.
  CanevasTemporaireActif.b = #True
  
  ; Déséléctionne tous les Objets du Canevas sauf celui sélectionné, un seul Objet doit être sélectionné et c'est celui don on est en train d'éditer l'image, sinon bug car plusieurs Objet sont sélectionné.
  
  ;{ Désélectionne l'Objet spécifié ou tous les Objets du Canevas spécifié.
  ;  iObject:               Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
	;                          - #Object_All:       Deselectionne tous les objets dans l'ordre.
	;                          - #Object_Selected:  Deselectionne tous les objets sélectionnés dans l'ordre.
  ;  iCanvasGadget:         Numéro du canevas pour restraindre la Deselection seulement à ce canevas, ou #PB_Ignore pour autoriser la Deselection de tous les objets peut importe ou il ce trouve.
	;  bPostEvent:            Par défaut (#False), aucun événement n'est déclenché. Utilisez #True pour déclencher le type d'événement #EventType_Unselected.
	;}
  UnselectObject(#Object_Selected, Canevas.i)
  
	;{ Sélectionne l'Objet spécifié ou tous les Objets du Canevas spécifié.
	;  iObject:               Numéro d'objet ou l'une des constantes suivantes:
	;                          - #Object_All: Itère à travers tous les objets dans l'ordre.
	;  iCanvasGadget:         Numéro du canevas gadget pour restreindre #Object_All au gadget spécifié, ou #PB_Ignore pour autoriser tous les gadgets.
	;  bPostEvent:            Par défaut (#False), aucun événement n'est déclenché. Utilisez #True pour déclencher le type d'événement #EventType_Selected.
	;}
  ; Sélectionne l'Objet en court d'édition.
  SelectObject(EventObject(Canevas.i), Canevas.i)
  
  ; Redimensionner et positionner le canevas temporaire pour correspondre à l'objet.
  ResizeGadget(#CanevasTemporaire, GetObjectX(EventObject(Canevas.i)) - 2, GetObjectY(EventObject(Canevas.i)) - 2, GetObjectWidth(EventObject(Canevas.i)) + 4, GetObjectHeight(EventObject(Canevas.i)) + 4)
  
  ; Vérifie si l'objet a une image associée comme Data.
  ImageObjetAdditionnelle.i = IsObjectImage(EventObject(Canevas.i))
  
  If ImageObjetAdditionnelle.i <> 0
    
    ; Récupérer les dimensions de l'objet.
    Largeur.i = ImageWidth(ImageObjetAdditionnelle.i)
    Hauteur.i = ImageHeight(ImageObjetAdditionnelle.i)
    
    ; Vérifie si une image temporaire existe déjà, sinon la recréer.
    If IsImage(#ImageCanevasTemporaire)
      
      ; Redimensionner l'image temporaire si nécessaire.
      If ImageWidth(#ImageCanevasTemporaire) <> Largeur.i Or ImageHeight(#ImageCanevasTemporaire) <> Hauteur.i
        FreeImage(#ImageCanevasTemporaire) ; Efface l'image temporaire car il faut la refaire car elle est trop petite !
        
        ; Création de l'image temporaire de la taille de l'Objet.
        If CreateImage(#ImageCanevasTemporaire, Largeur.i, Hauteur.i, 32, #PB_Image_Transparent)
          ; Debug "Image temporaire recréée avec les nouvelles dimensions."
          
        Else
          Debug "Erreur : Impossible de recréer l'image temporaire."
          ProcedureReturn 0
          
        EndIf
        
      EndIf
      
    Else
      
      ; Créer une nouvelle image temporaire si elle n'existe pas.
      If CreateImage(#ImageCanevasTemporaire, Largeur.i, Hauteur.i, 32, #PB_Image_Transparent)
        ; Debug "Image temporaire créée."
        
      Else
        Debug "Erreur : Impossible de créer l'image temporaire."
        ProcedureReturn 0
        
      EndIf
      
    EndIf
    
    ; Copier l'image de l'objet dans l'image temporaire.
    If StartDrawing(ImageOutput(#ImageCanevasTemporaire))
      DrawingMode(#PB_2DDrawing_AllChannels)
      Box(0, 0, Largeur.i, Hauteur.i, RGBA(255, 255, 255, 0)) ; Effacer avec transparence
      DrawImage(ImageID(ImageObjetAdditionnelle.i), 0, 0)     ; Dessiner l'image sans décalage
      StopDrawing()
      
      ; Debug "Image de l'objet n°" + Str(EventObject(Canevas.i)) + " copiée dans l'image temporaire."
      
    Else
      Debug "Erreur : Impossible de dessiner dans l'image temporaire."
      
    EndIf
    
    ; Mettre à jour le canevas temporaire avec l'image temporaire.
    SetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_Image, ImageID(#ImageCanevasTemporaire))
    ; Debug "Image temporaire affichée dans le canevas."
    
    ; Mémorise l'Objets en court d'édition.
    ActiveObject.i = EventObject(Canevas.i)
    
    ; Cache l'Objets en court d'édition.
    HideObject(ActiveObject.i, #Canevas)
    
  Else
    Debug "Aucune image associée à l'objet n°" + Str(EventObject(Canevas.i))
    
  EndIf
  
EndProcedure

; Quand un Objet est en train d'être déssiné grace au canevas temporaire.
Procedure WhenDrawObject()
  
  ; Il faut que le Canevas Temporaire soit activé.
  If CanevasTemporaireActif.b = #True
    
    ; Création d'une image temporaire pour dessiner
    Largeur.i = GadgetWidth(#CanevasTemporaire)
    Hauteur.i = GadgetHeight(#CanevasTemporaire)
    
    ; Vérifier si une image temporaire principale existe déjà, sinon la créer
    If Not IsImage(#ImageCanevasTemporaire)
      If CreateImage(#ImageCanevasTemporaire, Largeur.i, Hauteur.i, 32, #PB_Image_Transparent)
        ; Debug "Image temporaire principale créée."
      Else
        Debug "Erreur : Impossible de créer l'image temporaire principale."
      EndIf
    EndIf
    
    ; Si l'image temporaire est bien initialisée
    If IsImage(#ImageCanevasTemporaire)
      
      ; Quand le bouton gauche de la souris est cliqué
      If EventType() = #PB_EventType_LeftButtonDown
        ; Sauvegarde la position de la souris cliquée
        MouseClickX.i = GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_MouseX)
        MouseClickY.i = GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_MouseY)
        MouseMoveX.i = MouseClickX.i
        MouseMoveY.i = MouseClickY.i
        
        ; Quand la souris est en mouvement avec le bouton gauche enfoncé
      ElseIf EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
        
        MouseMoveX.i = GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_MouseX)
        MouseMoveY.i = GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_MouseY)
        
        If ModeDessin.i = 1
          
          ; Mode 1 : Dessiner des points directement sur l'image temporaire
          If StartDrawing(ImageOutput(#ImageCanevasTemporaire))
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            Circle(MouseMoveX.i, MouseMoveY.i, 3, RGBA(Random(255), Random(255), Random(255), TransparenceRondPleins.i)) ; Dessiner un cercle de couleur aléatoire
            StopDrawing()
            
            ; Mettre à jour le canevas avec l'image temporaire
            If StartDrawing(CanvasOutput(#CanevasTemporaire))
              DrawingMode(#PB_2DDrawing_AllChannels)
              Box(0, 0, Largeur.i, Hauteur.i, RGBA(255, 255, 255, 255)) ; Effacer le canevas
              DrawingMode(#PB_2DDrawing_AlphaBlend)
              DrawImage(ImageID(#ImageCanevasTemporaire), 0, 0)
              StopDrawing()
            EndIf
            
          Else
            Debug "Erreur : Impossible de dessiner des points sur l'image temporaire."
            
          EndIf
          
        ElseIf ModeDessin.i = 2
          
          ; Mode 2 : Dessiner temporairement un carré plein sur le canevas
          If StartDrawing(CanvasOutput(#CanevasTemporaire))
            DrawingMode(#PB_2DDrawing_AllChannels)
            Box(0, 0, Largeur.i, Hauteur.i, RGBA(255, 255, 255, 255)) ; Effacer le canevas
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(#ImageCanevasTemporaire), 0, 0)         ; Réappliquer l'image temporaire
            Box(MouseClickX.i, MouseClickY.i, MouseMoveX.i - MouseClickX.i, MouseMoveY.i - MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceCarrePleins.i)) ; Dessiner un carré plein
            StopDrawing()
            
          Else
            Debug "Erreur : Impossible de dessiner temporairement sur le canevas."
            
          EndIf
          
        ElseIf ModeDessin.i = 3
          
          ; Mode 3 : Dessiner temporairement un carré vide (encadrement seulement) sur le canevas
          If StartDrawing(CanvasOutput(#CanevasTemporaire))
            DrawingMode(#PB_2DDrawing_AllChannels)
            Box(0, 0, Largeur.i, Hauteur.i, RGBA(255, 255, 255, 255)) ; Effacer le canevas
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(#ImageCanevasTemporaire), 0, 0)         ; Réappliquer l'image temporaire
            
            ; Dessiner le carré vide (encadrement seulement)
            LineXY(MouseClickX.i, MouseClickY.i, MouseMoveX.i, MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i)) ; Ligne du haut
            LineXY(MouseMoveX.i, MouseClickY.i, MouseMoveX.i, MouseMoveY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i))   ; Ligne de droite
            LineXY(MouseMoveX.i, MouseMoveY.i, MouseClickX.i, MouseMoveY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i))   ; Ligne du bas
            LineXY(MouseClickX.i, MouseMoveY.i, MouseClickX.i, MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i)) ; Ligne de gauche
            StopDrawing()
            
          Else
            Debug "Erreur : Impossible de dessiner temporairement sur le canevas."
            
          EndIf
          
        EndIf
        
        ; Quand le bouton gauche de la souris est relâché
      ElseIf EventType() = #PB_EventType_LeftButtonUp
        
        If ModeDessin.i = 2 Or ModeDessin.i = 3
          
          ; Finaliser le dessin (plein ou vide) dans l'image temporaire
          If StartDrawing(ImageOutput(#ImageCanevasTemporaire))
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            
            If ModeDessin.i = 2
              ; Dessiner le carré plein
              Box(MouseClickX.i, MouseClickY.i, MouseMoveX.i - MouseClickX.i, MouseMoveY.i - MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceCarrePleins.i))
              
            ElseIf ModeDessin.i = 3
              ; Dessiner le carré vide (encadrement seulement)
              LineXY(MouseClickX.i, MouseClickY.i, MouseMoveX.i, MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i)) ; Ligne du haut
              LineXY(MouseMoveX.i, MouseClickY.i, MouseMoveX.i, MouseMoveY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i))   ; Ligne de droite
              LineXY(MouseMoveX.i, MouseMoveY.i, MouseClickX.i, MouseMoveY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i))   ; Ligne du bas
              LineXY(MouseClickX.i, MouseMoveY.i, MouseClickX.i, MouseClickY.i, RGBA(Random(255), Random(255), Random(255), TransparenceBordureCarreVide.i)) ; Ligne de gauche
            EndIf
            
            StopDrawing()
            
          Else
            Debug "Erreur : Impossible de finaliser le dessin dans l'image temporaire."
            
          EndIf
          
          ; Mettre à jour le canevas avec l'image temporaire mise à jour
          If StartDrawing(CanvasOutput(#CanevasTemporaire))
            DrawingMode(#PB_2DDrawing_AllChannels)
            Box(0, 0, Largeur.i, Hauteur.i, RGBA(255, 255, 255, 255)) ; Effacer le canevas
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(#ImageCanevasTemporaire), 0, 0)         ; Réappliquer l'image temporaire
            StopDrawing()
            
          Else
            Debug "Erreur : Impossible de mettre à jour le canevas."
          EndIf
          
        EndIf
        
      EndIf
      
    Else
      Debug "Image temporaire non initialisée."
      
    EndIf
    
    ; Vous pouvez utiliser aussi ceci:
    
    ;                 Select EventType()
    ;                     
    ;                   Case #PB_EventType_MouseEnter
    ;                     Debug "La souris est entrée sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_MouseLeave
    ;                     Debug "La souris est sortie du CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_LeftButtonDown
    ;                     Debug "Le bouton gauche de la souris a été appuyé sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_LeftButtonUp
    ;                     Debug "Le bouton gauche de la souris a été relâché sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_LeftClick
    ;                     Debug "Un clique gauche de la souris a eu lieu sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_LeftDoubleClick
    ;                     Debug "Un double clique gauche de la souris a eu lieu sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_MiddleButtonDown
    ;                     Debug "Le bouton du milieux de la souris a été appuyé sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_MiddleButtonUp
    ;                     Debug "Le bouton du milieux de la souris a été relâché sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_RightButtonDown
    ;                     Debug "Le bouton droit de la souris a été appuyé sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_RightButtonUp
    ;                     Debug "Le bouton droit de la souris a été relâché sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_RightClick
    ;                     Debug "Un clique droit de la souris a eu lieu sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_RightDoubleClick
    ;                     Debug "Un double clique droit de la souris a eu lieu sur le CanevasTemporaire"
    ;                     
    ;                   Case #PB_EventType_KeyDown
    ;                     Debug "La touche du clavier " + Chr(GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_Key)) + " a été enfoncée sur le CanevasTemporaire" ; Voir la Table Ascii.
    ;                     
    ;                   Case #PB_EventType_KeyUp
    ;                     Debug "La touche du clavier " + Chr(GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_Key)) + " a été relâché sur le CanevasTemporaire" ; Voir la Table Ascii.
    ;                     
    ;                   Case #PB_EventType_MouseWheel
    ;                     
    ;                     If GetGadgetAttribute(#CanevasTemporaire, #PB_Canvas_WheelDelta) > 0
    ;                       Debug "La molette de la souris a été tournée vers le haut sur le CanevasTemporaire"
    ;                     Else
    ;                       Debug "La molette de la souris a été tournée vers le bas sur le CanevasTemporaire"
    ;                     EndIf
    ;                     
    ;                 EndSelect
    
  EndIf
  
EndProcedure

; Quand un Objet est désélectionné.
Procedure WhenUnselectObject()
  
  If CanevasTemporaireActif.b = #True
    
    ; Récupère le numéro de l'objet.
    Object.i = EventObject(Canevas.i)
    
    ; L'objet a-t-il une image en tant que Data ? Si oui, la retourne, sinon retourne 0.
    ImageObjetAdditionnelle.i = IsObjectImage(Object.i)
    
    If ImageObjetAdditionnelle.i <> 0
      
      ; Vérifier si l'image temporaire du canevas existe
      If IsImage(#ImageCanevasTemporaire)
        
        ; Met à jour l'image additionnelle de l'objet avec le contenu du canevas temporaire.
        If StartDrawing(ImageOutput(ImageObjetAdditionnelle.i))
          DrawingMode(#PB_2DDrawing_AllChannels)
          
          ; Efface l'image additionnelle en transparent pour éviter les dessins superposés.
          Box(0, 0, ImageWidth(ImageObjetAdditionnelle.i), ImageHeight(ImageObjetAdditionnelle.i), RGBA(255, 255, 255, 0))
          
          ; Dessiner le contenu de l'image temporaire sur l'image additionnelle.
          DrawImage(ImageID(#ImageCanevasTemporaire), 0, 0)
          StopDrawing()
          
          ; Debug "Image Objet (" + Str(Object.i) + ") mise à jour avec succès : " + Str(ImageObjetAdditionnelle.i)
          
        Else
          Debug "Erreur : Impossible de dessiner sur l'image additionnelle de l'objet n°" + Str(Object.i)
          
        EndIf
        
      Else
        Debug "Erreur : Aucune image temporaire disponible pour mettre à jour l'objet."
        
      EndIf
      
    Else
      Debug "Aucune image associée à l'objet n°" + Str(Object.i)
      
    EndIf
    
    ; Désactive le canevas temporaire et le redimensionne pour le cacher.
    CanevasTemporaireActif.b = #False
    ResizeGadget(#CanevasTemporaire, -1, -1, 1, 1)
    
    ; Si un Objets est Actif.
    If ActiveObject.i > 0
      
      ; Cache l'Objets en court d'édition.
      ShowObject(ActiveObject.i, #Canevas)
      
    EndIf
    
  EndIf
  
EndProcedure

; Quand un Objet est redimentionné.
Procedure WhenResizeObject()
  
  ; Récupère le numéro de l'Objet.
  Object.i = EventObject(Canevas.i)
  
  ; L'Objet a-t-il une image en tant que Data ? Si oui, la retourne sinon retourne 0.
  ImageObjetAdditionnelle.i = IsObjectImage(Object.i)
  
  If ImageObjetAdditionnelle.i <> 0
    
    ; Obtenir les dimensions actuelles de l'image.
    LargeurActuelle.i = ImageWidth(ImageObjetAdditionnelle.i)
    HauteurActuelle.i = ImageHeight(ImageObjetAdditionnelle.i)
    
    ; Obtenir les nouvelles dimensions de l'objet.
    NouvelleLargeur.i = GetObjectWidth(Object.i)
    NouvelleHauteur.i = GetObjectHeight(Object.i)
    
    ; Vérifier si l'image doit être redimensionnée.
    If NouvelleLargeur.i > LargeurActuelle.i Or NouvelleHauteur.i > HauteurActuelle.i
      
      ; Créer une nouvelle image temporaire avec les dimensions nécessaires.
      TempImage.i = CreateImage(#PB_Any, NouvelleLargeur.i, NouvelleHauteur.i, 32, #PB_Image_Transparent)
      
      If TempImage.i
        
        ; Dessiner l'image actuelle centrée sur l'image temporaire.
        StartDrawing(ImageOutput(TempImage.i))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        Box(0, 0, NouvelleLargeur.i, NouvelleHauteur.i, RGBA(255, 255, 255, 0)) ; Effacer avec la transparence
        XOffset.i = (NouvelleLargeur.i - LargeurActuelle.i) / 2
        YOffset.i = (NouvelleHauteur.i - HauteurActuelle.i) / 2
        DrawImage(ImageID(ImageObjetAdditionnelle.i), XOffset.i, YOffset.i)
        StopDrawing()
        
        ; Redimensionner l'image additionnelle à la taille de l'image temporaire.
        ResizeImage(ImageObjetAdditionnelle.i, NouvelleLargeur.i, NouvelleHauteur.i)
        
        ; Effacer l'image additionnelle avec une couleur transparente.
        StartDrawing(ImageOutput(ImageObjetAdditionnelle.i))
        DrawingMode(#PB_2DDrawing_AllChannels)
        Box(0, 0, NouvelleLargeur.i, NouvelleHauteur.i, RGBA(255, 255, 255, 0))
        StopDrawing()
        
        ; Copier l'image temporaire sur l'image additionnelle.
        StartDrawing(ImageOutput(ImageObjetAdditionnelle.i))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        DrawAlphaImage(ImageID(TempImage.i), 0, 0, 255)
        StopDrawing()
        
        ; Effacer l'image temporaire.
        FreeImage(TempImage.i)
        
        ; Debug "Image Objet (" + Str(Object.i) + ") a été agrandie à " + Str(NouvelleLargeur.i) + "x" + Str(NouvelleHauteur.i)
        
      Else
        Debug "Erreur : Impossible de créer une image temporaire pour l'objet n°" + Str(Object.i)
        
      EndIf
      
    Else
      ; Debug "L'image de l'objet n°" + Str(Object.i) + " est plus petite ou égale à la taille actuelle. Aucun changement."
      
    EndIf
    
  Else
    Debug "Aucune image associée à l'objet n°" + Str(Object.i)
    
  EndIf
  
EndProcedure

; ----------------------------------------------

;{ Procédure Callback pour dessiner une image sur l'objet dans le Canevas car quand celui-ci est créer, il n'y a rien (Gris).
; MyDrawingObject = Le nom de la procédure personnalisé pour dessiner quelque chose sur l'objet voulut, donnez lui le nom que vous voulez mais elle devras obligatoirement avoir ces arguments: Object.i, Width.i, Height.i
; Les paramètres: (Object.i, Width.i, Height.i) seront automatiquement utiliser dans la procédure MyDrawingObject().
; Object.i est le numéro de l'objet, cette variable n’apparaît pas dans la procédure mais est indispensable.
; Width.i est la largeur de l'objet.
; Height.i est la hauteur de l'objet.
; iData.i est une donnée personnalisé, un chiffre ici (Couleur), n'est pas obligatoire, même dans les paramètre de la procédure, MyDrawingObject(Object.i, Width.i, Height.i) fonctionne aussi.
;}
; Cette procédure va dessiner ou redessiner automatiquement le contenu de cette procédure sur l'Objet à chaque fois que ce sera nécessaire.
Runtime Procedure MyDrawingObject(Object.i, Width.i, Height.i, iData.i)
  
  ; Graphique de base.
  AddPathBox(0.5, 0.5, Width - 1, Height - 1)
  VectorSourceColor(RGBA(255, 255, 255, 255))
  FillPath()
  AddPathBox(0.5, 0.5, Width-1, Height-1)
  VectorSourceColor(iData|$80000000)
  FillPath(#PB_Path_Preserve)
  VectorSourceColor(iData|$FF000000)
  StrokePath(1)
  
  ; L'Objet a t-il une image en tans que Data ?, si oui la retourne sinon retourne 0
  ImageObjetAdditionnelle.i = IsObjectImage(Object.i)
  
  If ImageObjetAdditionnelle.i <> 0
    ; Debug "Image Objet (" + Str(Object.i) + ") ok et déssiné dans MyDrawingObject: " + Str(ImageObjetAdditionnelle.i)
    ; déssine cette image par dessus les graphique de l'Objet, cette nouvelle image sera centré sur l'Objet.
    MovePathCursor(((Width.i - ImageWidth(ImageObjetAdditionnelle.i)) / 2), (Height.i - ImageHeight(ImageObjetAdditionnelle.i)) / 2)
    DrawVectorImage(ImageID(ImageObjetAdditionnelle.i), 255, ImageWidth(ImageObjetAdditionnelle.i), ImageHeight(ImageObjetAdditionnelle.i))
  EndIf
  
EndProcedure

; ----------------------------------------------

; Création d'une fenêtre.
OpenWindow(#Window, 0, 0, 800, 450, "Déssiner sur des Objets avec diverses Mode avec la souris grace a un Canevas Temporaire", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

; Création d'un Canevas gadget.
CanvasGadget(#Canevas, 0, 0, WindowWidth(#Window) - 50, WindowHeight(#Window), #PB_Canvas_Keyboard | #PB_Canvas_Container)

; Création d'un canevas temporaire qui servira à déssiner sur un Objets.
CanvasGadget(#CanevasTemporaire, -1, -1, 1, 1, #PB_Canvas_Border)

CloseGadgetList()

; Bouton mode de déssin 1 = Rond.
ButtonGadget(#BoutonDessinMode1, WindowWidth(#Window) - 40, 10, 32, 32, "1", #PB_Button_Toggle)

; Bouton mode de déssin 2 = Carré pleins.
ButtonGadget(#BoutonDessinMode2, WindowWidth(#Window) - 40, 45, 32, 32, "2", #PB_Button_Toggle)

; Bouton mode de déssin 3 = Carrré vide avec bordures.
ButtonGadget(#BoutonDessinMode3, WindowWidth(#Window) - 40, 80, 32, 32, "3", #PB_Button_Toggle)

; Active le bouton 1.
SetGadgetState(#BoutonDessinMode1, #True)

;{ Initialise le gestionnaire d'Objets pour le Canevas gadget spécifié dans la fenêtre spécifiée, doit être fait pour chaque Canevas gadget.
;  iCanvasGadget:         PB Numéro du Canevas gadget.
;  iWindow:               PB Numéro de fenêtre.
;  Résulta:               Renvoie #True, si l'initialisation a réussi, sinon, #False.
;}
; Initialise la gestion pour le Canevas gadget.
InitializeCanvasObjects(#Canevas, #Window)

;{ Crée et ajoute un Objet au Canevas spécifié. ATTENTION: InitializeCanvasObjects() doit être appelé avant d'ajouter des Objets à ce Canevas.
;  iCanvasGadget:         PB Numéro du gadget Canevas.
;  iObject:               Un Numéro de l'Objet auto-défini ou #PB_Any pour générer un numéro unique. Le nombre auto-défini doit être compris entre 1 et 65535.
;  iX, iY:                La position de l'Objet sur le Canevas.
;  iWidth, iHeight:       La taille de l'Objet sur le Canevas.
;	 iParentObject:         Un numéro d'objet valide auquel l'objet doit être rattaché (facultatif). Par défaut, l'objet sera placé sur le cadre de la toile.
;  iFrameIndex:           Un index du cadre (commençant par 0) ou l'une des constantes suivantes, dans lequel l'objet doit être attaché (facultatif).
;                          - #Frame_NoFrame:     L'objet sera attaché au cadre standard non indexé (cadre pour les pièces jointes).
;                          - #Frame_ViewedFrame: L'objet sera attaché au cadre indexé actuellement affiché.
;  Résultat:              Le numéro d'objet de l'objet créé ou 0 si la création a échoué. 
;}
; Les #Objet ont été crée sur le #Canevas, mais ici sont vides (Gris et sans poignées).
; Les paramètres suivant: iParentObject et iFrameIndex, n'ont pas d'utilité dans cet exemple-ci, nous verront cela plus tard dans un autre exemple !
CreateObject(#Canevas, #Objet1, 20, 20, 120, 80)
CreateObject(#Canevas, #Objet2, 150, 20, 120, 80)
CreateObject(#Canevas, #Objet3, 20, 110, 120, 80)
CreateObject(#Canevas, #Objet4, 150, 110, 120, 80)

;{ Création des images totalement transparente qui seront déssiné par dessus les graphiques de base des Objets, ceci est un exemple, déssinez ce que vous voulez dedans, ou rien.
If CreateImage(#ImageObjet1, GetObjectWidth(#Objet1), GetObjectHeight(#Objet1), 32, #PB_Image_Transparent)
  
  If StartVectorDrawing(ImageVectorOutput(#ImageObjet1))
    
    Largeur.i = 90
    Hauteur.i = 60
    
    VectorSourceColor(RGBA(255, 0, 0, 255))
    
    ; Créer un carré rouge.
    AddPathBox((ImageWidth(#ImageObjet1) - Largeur.i) / 2, (ImageHeight(#ImageObjet1) - Hauteur.i) / 2, Largeur.i, Hauteur.i)
    
    ; créer un carré transparent.
    AddPathBox(((ImageWidth(#ImageObjet1) - Largeur.i) / 2) + 1, ((ImageHeight(#ImageObjet1) - Hauteur.i) / 2) + 1, Largeur.i - 2, Hauteur.i - 2)
    
    FillPath() ; Remplie que le carré rouge.
    
    StopVectorDrawing()
    
  EndIf
  
  SetObjectData(#Objet1, #ImageObjet1)
  
Else
  Debug "Ne peu pas créer l'image de l'Objets n°1"
  
EndIf

If CreateImage(#ImageObjet2, GetObjectWidth(#Objet2), GetObjectHeight(#Objet2), 32, #PB_Image_Transparent)
  
  If StartVectorDrawing(ImageVectorOutput(#ImageObjet2))
    
    Largeur.i = 90
    Hauteur.i = 60
    
    VectorSourceColor(RGBA(0, 150, 0, 255))
    
    ; Créer un carré vert.
    AddPathBox((ImageWidth(#ImageObjet2) - Largeur.i) / 2, (ImageHeight(#ImageObjet2) - Hauteur.i) / 2, Largeur.i, Hauteur.i)
    
    ; créer un carré transparent.
    AddPathBox(((ImageWidth(#ImageObjet2) - Largeur.i) / 2) + 1, ((ImageHeight(#ImageObjet2) - Hauteur.i) / 2) + 1, Largeur.i - 2, Hauteur.i - 2)
    
    FillPath() ; Remplie que le carré rouge.
    
    StopVectorDrawing()
    
  EndIf
  
  SetObjectData(#Objet2, #ImageObjet2)
  
Else
  Debug "Ne peu pas créer l'image de l'Objets n°2"
  
EndIf

If CreateImage(#ImageObjet3, GetObjectWidth(#Objet3), GetObjectHeight(#Objet3), 32, #PB_Image_Transparent)
  
  If StartVectorDrawing(ImageVectorOutput(#ImageObjet3))
    
    Largeur.i = 90
    Hauteur.i = 60
    
    VectorSourceColor(RGBA(0, 0, 255, 255))
    
    ; Créer un carré bleu.
    AddPathBox((ImageWidth(#ImageObjet3) - Largeur.i) / 2, (ImageHeight(#ImageObjet3) - Hauteur.i) / 2, Largeur.i, Hauteur.i)
    
    ; créer un carré transparent.
    AddPathBox(((ImageWidth(#ImageObjet3) - Largeur.i) / 2) + 1, ((ImageHeight(#ImageObjet3) - Hauteur.i) / 2) + 1, Largeur.i - 2, Hauteur.i - 2)
    
    FillPath() ; Remplie que le carré rouge.
    
    StopVectorDrawing()
    
  EndIf
  
  SetObjectData(#Objet3, #ImageObjet3)
  
Else
  Debug "Ne peu pas créer l'image de l'Objets n°3"
  
EndIf

If CreateImage(#ImageObjet4, GetObjectWidth(#Objet4), GetObjectHeight(#Objet4), 32, #PB_Image_Transparent)
  
  If StartVectorDrawing(ImageVectorOutput(#ImageObjet4))
    
    Largeur.i = 90
    Hauteur.i = 60
    
    VectorSourceColor(RGBA(255, 200, 0, 255))
    
    ; Créer un carré jaune.
    AddPathBox((ImageWidth(#ImageObjet4) - Largeur.i) / 2, (ImageHeight(#ImageObjet4) - Hauteur.i) / 2, Largeur.i, Hauteur.i)
    
    ; créer un carré transparent.
    AddPathBox(((ImageWidth(#ImageObjet4) - Largeur.i) / 2) + 1, ((ImageHeight(#ImageObjet4) - Hauteur.i) / 2) + 1, Largeur.i - 2, Hauteur.i - 2)
    
    FillPath() ; Remplie que le carré rouge.
    
    StopVectorDrawing()
    
  EndIf
  
  SetObjectData(#Objet4, #ImageObjet4)
  
Else
  Debug "Ne peu pas créer l'image de l'Objets n°4"
  
EndIf
;}

; Ici chaque objet aurra la même procédure de déssins avec juste une couleur comme paramètre.
; Il est tout à fait possible d'utiliser une procédure de déssins propre à chaque Objets !
; Pour cella, il suffie de créé une procédure pour chaque Objets !

;{  Définit une procédure de dessin personnalisée pour l'Objet spécifié.
;  iObject:               Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
;                          - #Object_Default: Définie l'image par defaut de tous les nouveaux objets créé.
;                          - #Object_All: Définie l'image de tous les objets.
;                          - #Object_Selected: Définie l'image de tous les objets sélectionnés.
;  sCallbackName:         Une chaîne vide ou un nom de procédure d'exécution valide vers une procédure avec les arguments suivants: Callback(iObject.i, iWidth.i, iHeight.i, iData.i)
;                          - iObject contient le numéro de l'Objet.
;                          - iWidth contient la largeur actuelle.
;                          - iHeight contient la hauteur actuelle.
;                          - iData contient une donnée utilisateur personnalisée (Nombre) individuelle qui sera également envoyée à la fonction.
;  Résultat:              Renvoie #True si le callback a été défini avec succet à l'Objet ou #False si l'Objet n'existe pas.
;}
; Dessine un carré remplie ainsi qu'une bordure avec la procedure MyDrawing().
SetObjectDrawingCallback(#Objet1, "MyDrawingObject()", RGB(242, 186, 40))  ; Jaune
SetObjectDrawingCallback(#Objet2, "MyDrawingObject()", RGB(241, 64, 33))   ; Rouge
SetObjectDrawingCallback(#Objet3, "MyDrawingObject()", RGB(130, 222, 29))  ; Vert
SetObjectDrawingCallback(#Objet4, "MyDrawingObject()", RGB(42, 53, 255))   ; Bleu

;{ Ajoute une ou plusieurs poignée standard ou personnalisée à l'Objet spécifié. Les poignées personnalisées peuvent avoir un alignement et un décalage de position.
;  iObject:          Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
;                     - #Object_Default: Définie les poignées par defaut de tous les nouveaux objets créé.
;                     - #Object_All: Définie les poignées de tous les objets.
;                     - #Object_Selected: Définie les poignées de tous les objets sélectionnés.
;  eType:            Une combinaison de tous les types de poignées qu'il faut ajouter. *
;  iImage:           Un numéro d'image pour la poignée. Par défaut (#PB_Default) l'image par défaut de la poignée est utilisée.
;  eAlignment:       L'alignement de la poignée personnalisée. Par défaut c'est #Alignment_Default = #Alignment_Center **
;  iX, iY:           Position décalée de la poignée par rapport à l'alignement et à l'Objet.
;  Resulta:          Renvoie #True, si l'ajout de la poignée a réussi, sinon #False.
;                  
;                  * Les types de poignées suivantes peuvent être utilisés et combinés:
;                    #Handle_Position:  Une poignée pour déplacer l'Objet.
;                    #Handle_Rotation:  Une poignée pour faire tourner l'Objet. (NON UTILISÉ).
;                    #Handle_BottomLeft, #Handle_Bottom, #Handle_BottomRight, #Handle_Left, #Handle_Right, #Handle_TopLeft, #Handle_Top, #Handle_TopRight:  Une poignée Pour redimensionner l'Objet dans cette direction.
;                    #Handle_Custom1 ... #Handle_Custom8: Une poignée personnalisée:
;                    
;                    En outre, les constantes suivantes sont des combinaisons prédéfinies:
;                    #Handle_Width  = #Handle_Left | #Handle_Right.
;                    #Handle_Height = #Handle_Top | #Handle_Bottom.
;                    #Handle_Edge   = #Handle_Width | #Handle_Height.
;                    #Handle_Corner = #Handle_BottomLeft | #Handle_BottomRight | #Handle_TopLeft | #Handle_TopRight.
;                    #Handle_Size   = #Handle_Edge | #Handle_Corner.
;                 
;                 ** Les types d'alignement suivants peuvent être utilisés et combinés:
;                    #Alignment_Top:     Aligne le centre de la poignée sur le bord supérieur de l'Objet.
;                    #Alignment_Bottom:  Aligne le centre de la poignée sur le bord inférieur de l'Objet.
;                    #Alignment_Left:    Aligne le centre de la poignée sur le bord gauche de l'Objet.
;                    #Alignment_Right:   Aligne le centre de la poignée sur le bord droit de l'Objet.
;                    #Alignment_Center:  Aligne le centre de la poignée sur le centre (x et/ou y) de l'Objet.
;}
; Quelques exemples non exhaustifs de poignées d'Objets.
AddObjectHandle(#Object_All, #Handle_Size | #Handle_Position) ; Redimentionnable dans toutes les direction et déplaçable.

;{ Définit le style du cadre de sélection du curseur de la souris.
;  iCanvasGadget.i        Le numéro du Canevas gadget.
;  eType :                Un des types de style suivants:
;                          - #SelectionStyle_None: Masque le cadre de sélection.
;                          - #SelectionStyle_Solid: ligne de cadre solide.
;                          - #SelectionStyle_Dotted: Ligne de cadre en pointillés.
;                          - #SelectionStyle_Dashed:  Dahsed frame line.
;                          - #SelectionStyle_Ignore:  Ignorer ce paramètre.
;                          - #SelectionStyle_Partially: Vous pouvez combiner cette constante (|) avec le type de style pour permettre la sélection par partiel.
;  iColor:                Couleur RGBA du cadre ou #SelectionStyle_Ignore pour ignorer ce paramètre.
;  dThickness :           Epaisseur de la ligne du cadre ou #SelectionStyle_Ignore pour ignorer ce paramètre.
;  iBackgroundColor.i     La couleur à l’intérieur de la sélection ou #SelectionStyle_Ignore pour ignorer ce paramètre.
;}
; Active et personnalise la sélection du curseur de la souris pour sélectionné les Objets sur le Canevas gadget.
; Ajoutez #SelectionStyle_Partially pour sélectionner les Objets si la sélection touche l'Objets avec |, par défaut, la sélection dois entourer complètement l'objet pour le sélectionner.
SetCursorSelectionStyle(#Canevas, #SelectionStyle_Dotted, RGBA(0, 0, 0, 255), 1, 0) 

;{ Définit le style du cadre de sélection de l'Objet spécifié.
;  iObject:               Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
;                          - #Object_Default: Définie le style de selection par defaut de tous les nouveaux objets créé.
;                          - #Object_All: Définie le style de selection de tous les objets.
;                          - #Object_Selected: Définie le style de selection de tous les objets sélectionnés.
;  eType:                 Un des types de style suivants:
;                          - #SelectionStyle_Default: Utilise le style par défaut.
;                          - #SelectionStyle_None: Masque le cadre de sélection.
;                          - #SelectionStyle_Solid: ligne en continue.
;                          - #SelectionStyle_Dotted: ligne en Pointillés.
;                          - #SelectionStyle_Dashed: ligne tiret.
;  iColor:                Couleur RGBA du cadre ou #SelectionStyle_Ignore pour ignorer ce paramètre. Non utilisé si eType est #SelectionStyle_Default ou #SelectionStyle_None.
;  dThickness:            Epaisseur de la ligne de cadre ou #SelectionStyle_Ignore pour ignorer ce paramètre. Non utilisé si eType est #SelectionStyle_Default ou #SelectionStyle_None.
;  dDistance:             Distance de la ligne du cadre à la bordure de l'objet ou #SelectionStyle_Ignore pour ignorer ce paramètre.
;  Résultat:              #True si l'état du cadre sélectionné a été défini ou #False si l'objet n'existe pas.
;}
; Seléction avec des tirets.
SetObjectSelectionStyle(#Object_All, #SelectionStyle_Dashed, RGBA(0, 0, 0, 255), 1, 0)

;{ Définit la taille et la position limite de l'Objet spécifié.
;  iObject:               Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
;                          - #Object_Default: Définie les limites pour tous les nouveaux objets créé.
;                          - #Object_All: Définie les limites de tous les objets éxistant.
;                          - #Object_Selected: Définie les limites de tous les objets sélectionnés.
;  iMinX, iMinY:          Valeurs minimales pour la position de l'objet (en haut à gauche). *
;  iMaxX, iMaxY:          Valeurs maximales pour la position de l'objet (coin inférieur droit). *
;  iMinWidth, iMinHeight: Valeurs minimales pour la taille de l'objet. *
;  iMaxWidth, iMaxHeight: Valeurs maximales pour la taille de l'objet. *
;  Résultat:              #True si les limites ont été fixées ou #False si l'objet n'existe pas.
;                         * Pour les valeurs de taille et de position, les constantes suivantes peuvent également être utilisées:
;                           #Boundary_Ignore:      Ignorer ce paramètre et laisser la valeur limite inchangée.
;                           #Boundary_None:        Supprime la valeur limite de ce paramètre.
;                           #Boundary_ParentSize:  Ajoutez cette constante à une valeur de limite (#Boundary_ParentSize ± Valeur) pour rendre la limite relative à la taille du cadre parent (ou du canevas gadget).
;                           #Boundary_Default:     Régler la valeur limite à la valeur par défaut.
;}
; Limite la position ainsi que la taille, minimale et maximale des Objets.
SetObjectBoundaries(#Object_All, 0, 0, GadgetWidth(#Canevas), GadgetHeight(#Canevas))

;{ Définit le curseur de la souris affiché quand la souris passe sur l'objet spécifié.
; Cette fonction est à utiliser pour les fonctions suivante: SetObjectHandleCursor() et SetCanvasCursor(), pour le paramètre hCursorHandle.
; iObject:               Le numéro de l'Objet, les constantes suivantes peuvent être utilisées à la place du numéro de l'objet.
;                          - #Object_Default: Définie le curseur de la souris par defaut de tous les nouveaux objets créé.
;                          - #Object_All: Définie le curseur de la souris de tous les objets.
;                          - #Object_Selected: Définie le curseur de la souris de tous les objets sélectionnés.
;  eCursor:               Une constante #PB_Cursor_* valide:
;                         #PB_Cursor_Default            : Flèche du curseur par défaut 
;                         #PB_Cursor_Cross              : Curseur en forme de croix 
;                         #PB_Cursor_IBeam              : Barre d'insertion 'I' utilisée pour la sélection de texte  
;                         #PB_Cursor_Hand               : Curseur main 
;                         #PB_Cursor_Busy               : Curseur sablier ou une montre 
;                         #PB_Cursor_Denied             : Curseur cercle barré ou curseur X 
;                         #PB_Cursor_Arrows             : Flèches dans toutes les directions (non disponible sur OS X) 
;                         #PB_Cursor_LeftRight          : Flèches gauche et droite 
;                         #PB_Cursor_UpDown             : Flèches haut et bas 
;                         #PB_Cursor_LeftUpRightDown    : Flèches diagonales (Windows uniquement) 
;                         #PB_Cursor_LeftDownRightUp    : Flèches diagonales (Windows uniquement)  
;                         #PB_Cursor_Invisible          : Cache le curseur
;                         #PB_Cursor_Custom             : Un Curseur personnalisé
;  hCursorHandle:        Une image personnalisé pour le curseur, a condition que eCursor soit #PB_Cursor_Custom.
;  Résultat:             Renvoie #True si le curseur a été placé ou #False si l'objet n'existe pas.
;}
; Curseur Personnalisé.
SetObjectCursor(#Object_All, #PB_Cursor_Hand)


; La boucle événementielle de la fenêtre et les gadgets.
Repeat
  
  WindowEvent = WaitWindowEvent(1) ; Cette ligne attend pendent (Minuteur) qu'un évènement soit recus par la fenêtre
  WindowID = EventWindow()         ; La fenêtre où l'évènement c'est produit
  GadgetID = EventGadget()         ; Pour savoir sur quel gadget c'est produis l'évènement
  MenuID = EventMenu()             ; Pour savoir sur quel menue c'est produis l'évènement
  EventType = EventType()          ; Le type d'évènement qui c'est produis sur le gadget
  
  Select WindowID
      
    Case #Window
      
      Select WindowEvent 
          
        Case #PB_Event_Gadget
          
          Select GadgetID
              
            Case #Canevas
              
              Select EventType()
                  
                Case #PB_EventType_MouseEnter
                  Debug "La souris est entrée sur le Canevas"
                  
                Case #PB_EventType_MouseLeave
                  Debug "La souris est sortie du Canevas"
                  
                Case #PB_EventType_LeftButtonDown
                  Debug "Le bouton gauche de la souris a été appuyé sur le Canevas"
                  
                Case #PB_EventType_LeftButtonUp
                  Debug "Le bouton gauche de la souris a été relâché sur le Canevas"
                  
                Case #PB_EventType_LeftClick
                  Debug "Un clique gauche de la souris a eu lieu sur le Canevas"
                  
                Case #PB_EventType_LeftDoubleClick
                  Debug "Un double clique gauche de la souris a eu lieu sur le Canevas"
                  
                Case #PB_EventType_MiddleButtonDown
                  Debug "Le bouton du milieux de la souris a été appuyé sur le Canevas"
                  
                Case #PB_EventType_MiddleButtonUp
                  Debug "Le bouton du milieux de la souris a été relâché sur le Canevas"
                  
                Case #PB_EventType_RightButtonDown
                  Debug "Le bouton droit de la souris a été appuyé sur le Canevas"
                  
                Case #PB_EventType_RightButtonUp
                  Debug "Le bouton droit de la souris a été relâché sur le Canevas"
                  
                Case #PB_EventType_RightClick
                  Debug "Un clique droit de la souris a eu lieu sur le Canevas"
                  
                Case #PB_EventType_RightDoubleClick
                  Debug "Un double clique droit de la souris a eu lieu sur le Canevas"
                  
                Case #PB_EventType_KeyDown
                  Debug "La touche du clavier " + Chr(GetGadgetAttribute(#Canevas, #PB_Canvas_Key)) + " a été enfoncée sur le Canevas" ; Voir la Table Ascii.
                  
                Case #PB_EventType_KeyUp
                  Debug "La touche du clavier " + Chr(GetGadgetAttribute(#Canevas, #PB_Canvas_Key)) + " a été relâché sur le Canevas" ; Voir la Table Ascii.
                  
                Case #PB_EventType_MouseWheel
                  
                  If GetGadgetAttribute(#Canevas, #PB_Canvas_WheelDelta) > 0
                    Debug "La molette de la souris a été tournée vers le haut sur le Canevas"
                  Else
                    Debug "La molette de la souris a été tournée vers le bas sur le Canevas"
                  EndIf
                  
              EndSelect
              
            Case #CanevasTemporaire
              ; Quand on est en train de déssiner sur l'Objet.
              WhenDrawObject()
              
            Case #BoutonDessinMode1
              
              If GetGadgetState(#BoutonDessinMode1) = #False
                SetGadgetState(#BoutonDessinMode1, #True)
              EndIf
              
              SetGadgetState(#BoutonDessinMode2, #False)
              SetGadgetState(#BoutonDessinMode2, #False)
              
              ModeDessin.i = 1
              
            Case #BoutonDessinMode2
              
              If GetGadgetState(#BoutonDessinMode2) = #False
                SetGadgetState(#BoutonDessinMode2, #True)
              EndIf
              
              SetGadgetState(#BoutonDessinMode1, #False)
              SetGadgetState(#BoutonDessinMode3, #False)
              
              ModeDessin.i = 2
              
            Case #BoutonDessinMode3
              
              If GetGadgetState(#BoutonDessinMode3) = #False
                SetGadgetState(#BoutonDessinMode3, #True)
              EndIf
              
              SetGadgetState(#BoutonDessinMode1, #False)
              SetGadgetState(#BoutonDessinMode2, #False)
              
              ModeDessin.i = 3
              
          EndSelect
          
        Case #PB_Event_Menu
          
          Select MenuID
              
            Case 0
              
          EndSelect
          
        Case #PB_Event_CloseWindow  
          End
          
      EndSelect
      
  EndSelect
  
  ; Boucle d'évènement des Objets dans le Canevas.
  Repeat
    
    Select CanvasObjectsEvent() ;  Quelque chose s'est passé dans un Canevas.
        
      Case #Event_Object ; C'est un Evénements de type Objets.
        
        Canevas.i = CanvasObjectsEventGadget() ; Sur quel Canevas s'est passé l'évènement ?
        
        Select CanvasObjectsEventType(Canevas.i) ; Quel type d’Événements s'est passé sur l'Objet du Canevas ?
            
          Case #EventType_MouseEnter
            Debug "La souris est entrée sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_MouseLeave
            Debug "La souris est sortie de l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_LeftMouseBottonDown
            Debug "Le bouton gauche de la souris a été appuyé sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_LeftMouseBottonUp
            Debug "Le bouton gauche de la souris a été relâché sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_LeftMouseClick
            Debug "Un clique gauche de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_LeftMouseDoubleClick
            Debug "Un double-clic gauche de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            ; Quand on double clique sur un Objet, active le canevas temporaire puis affiche l'image de l'Objet dedans pour la modifier.
            WhenDoubleClickedObject()
            
          Case #EventType_MiddleMouseBottonDown
            Debug "Le bouton du milieux de la souris a été appuyé sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_MiddleMouseBottonUp
            Debug "Le bouton du milieux de la souris a été relâché sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_MiddleMouseClick
            Debug "Un clique centre de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_MiddleMouseDoubleClick
            Debug "Un double clique centre de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_RightMouseBottonDown
            Debug "Le bouton droit de la souris a été appuyé sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_RightMouseBottonUp
            Debug "Le bouton droit de la souris a été relâché sur l'Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_RightMouseClick
            Debug "Un clique droit de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_RightMouseDoubleClick
            Debug "Un double clique droit de la souris a eu lieu sur l’Objet n°" + EventObject(Canevas.i)
            
          Case #EventType_MouseWheel
            
            If CanvasObjectsEventData(Canevas.i) > 0
              Debug "La molette de la souris a été tournée vers le haut sur l'Objet n°" + EventObject(Canevas.i)
            Else
              Debug "La molette de la souris a été tournée vers le bas sur l'Objet n°" + EventObject(Canevas.i)
            EndIf
            
          Case #EventType_KeyUp
            Debug "La touche du clavier " + Chr(CanvasObjectsEventData(Canevas.i)) + " a été enfoncée sur  l'Objet n°" + EventObject(Canevas.i) ; Voir la Table Ascii.
            
          Case #EventType_KeyDown
            Debug "La touche du clavier " + Chr(CanvasObjectsEventData(Canevas.i)) + " a été relâché sur  l'Objet n°" + EventObject(Canevas.i) ; Voir la Table Ascii.
            
          Case #EventType_Selected
            Debug "L'Objet n°" + EventObject(Canevas.i) + " a été sélectionné."
            
          Case #EventType_Unselected ; Si un objet a été désélectionné, cache le canevas temporaire s'il est actif.
            Debug "L'Objet n°" + EventObject(Canevas.i) + " a été désélectionné."
            ; Quand on clique en dehor du Canevas temporaire, pour valider les changement, l'image de l'Objet est alors mise à jour.
            WhenUnselectObject()
            
          Case #EventType_Resized
            Debug "L'Objet n°" + EventObject(Canevas.i) + " a été redimensionné."
            ; Quand un Objet est redimentionné, agrandis l'image de l'Objet si celle-ci est plus petite, sinon ne fait rien. 
            WhenResizeObject()
            
            ; Subtilité ici avec cette fonction !
            ShowObject(EventObject(Canevas.i)) ; Déclenche un repeint de l'Objet sur le Canevas.
            
          Case #EventType_Selection
            X.i = CanvasObjectsEventData(Canevas.i, #EventTypeData_MinX)
            Y.i = CanvasObjectsEventData(Canevas.i, #EventTypeData_MinY)
            Largeur.i = CanvasObjectsEventData(Canevas.i, #EventTypeData_MaxX) - X.i
            Hauteur.i = CanvasObjectsEventData(Canevas.i, #EventTypeData_MaxY) - Y.i
            Debug "Une séléction à été déssiné: ({X: " + Str(X.i) + ", Y: " + Str(Y.i) + "}, {Largeur: " + Str(Largeur.i) + ", Hauteur: " + Str(Hauteur.i) + "})"
            
        EndSelect
        
      Case #Event_None ; Pas d’Événements.
        Break          ; A ne jamais omettre ou sinon le programme tournera en boucle !
        
    EndSelect
    
  ForEver
  
ForEver
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
The Gost
User
User
Posts: 11
Joined: Fri Jan 03, 2025 5:35 pm

Re: EditorFactory - Module for object management in a Canvas

Post by The Gost »

Hello Stargate and ShadowStorm,

@ShadowStorm:
GetObjectImage() ? or GetObjectDrawing() (I think that's pretty good, don't you?)

The Gost, We can use the canvas by doing a GrabImage(), you know the position of your object and its size, so it’s easy.
But then, maybe you want the image exactly as it is displayed on the object, and that’s different...
because the canvas has a white background, and your object’s image might have fully transparent parts.
Ah yes, why not, see if it can be done...

@Stargate:
No, because the objects have no own image by default. It would be inefficient to first draw the object on an image
and then draw this image again on the canvas, if you instead draw the object directly on the canvas.

If you still need your own image as a drawing surface, create it yourself, here is an example:
You can draw on both objects or (when the toggle button is pressed) you can move and resize both objects.
Expressing feature requests and wishes is of cause welcomed. However, it is up to the programmer to decide if a feature
is easy to implement or impossible. ObjectMouseX() is of course easy to implement, it's one line of code.
Object rotation is impossible, because the module, drawing and event pipeline was not designed for such thinks and have to re-coded from scratch.
However, at the moment I have no time and no desire (I admit this openly) to work on this module.
I just can give small support (help or bug fixes) of the published version, which I did in the previous posts.
Ah, I see...
Ok, there's no other way so I guess to get the image of the object.

Thank you very much for your example, it's not bad at all !
With this example, I've got a basic model, so I should be able to do something with it !

Yes I understand Stargate, no worries, after all, it's your time and it's
precious, and it's with gratitude that I reply to thank you for this module.

Whahoo, great code @ShadowStorm, you did this just for me, what a kindness, I don't know what to say, thank you so much!
I think it took you some time to do it, it works well and it's something like this that I wanted, I'm spoiled between you and Stargate again thank you both ^^
Your code @ShadowStorm is complicated for me, but it works very well.
Well, I have to study all this.
ShadowStorm
Enthusiast
Enthusiast
Posts: 303
Joined: Tue Feb 14, 2017 12:07 pm

Re: EditorFactory - Module for object management in a Canvas

Post by ShadowStorm »

Hi The Gost,

I'd like to thank you for the example, I made it for you but not only that, it's useful.

Yes, it's true that it's not necessarily very simple, but it's not so complicated to use it either, because everything's already set up, you just have to modify a few things to suit your needs, like the Object input images (the Object creation image), and the WhenDrawObject() procedure, which will do the job when you want to modify the drawing of your Object, which isn't the simplest, but remains accessible to anyone familiar with Drawing2D, because with all these drawing modes, it's not easy to apply graphics to an image or surface. You just have to pay close attention to what you're doing, and read the relevant documentation carefully.

You may also need to modify the WhenResizeObject() procedure; currently, the image of the Object is only enlarged if the Object is enlarged, but if you reduce its size, the image of the Object keeps its current size to maintain its quality, and perhaps also the Object drawing procedure; currently, the image of the Object is always centered on it, regardless of its size, just as when the Object is enlarged, the image of it will be centered.

If you need any help, I'm here to help you too :)
I am French, I do not speak English.
My apologies for the mistakes.

I have sometimes problems of expression
I am sometimes quite clumsy, please excuse me and let me know.
Post Reply