CanvasDrawingManager

Programmation d'applications complexes
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Grosse mise à jours, premier post mis à jour.
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Salut, j'ai juste remis à jour le liens qui ne fonctionnais pas.
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Avatar de l’utilisateur
SPH
Messages : 4937
Inscription : mer. 09/nov./2005 9:53

Re: CanvasDrawingManager

Message par SPH »

Y a t'il une différence entre CanvasDrawingManager et Editor Factory , ou bien, est-ce un autre logiciel ? :?:

!i!i!i!i!i!i!i!i!i!
!i!i!i!i!i!i!
!i!i!i!
//// Informations ////
Intel Core i7 4770 64 bits - GTX 650 Ti
Version de PB : 6.12LTS- 64 bits
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Non, ça n'as rien à voir du tous, ce dernier est 100% de moi.
Ya pas d'objets a gérer dedans.

En gros imagine juste un canevas avec une procédure de dessins pour celui-ci.
dans ta procédure, tu met t'es fonction de dessins puis le code actualise automatiquement le canevas.

Vois ça un peu comme un espèce d'écran, tu sais comme pour les jeux vidéo a faire avec PB.
Pour chaque FPS = une boucle.

Tu peu télécharger et essayer, ce sera mieux si tu as l'archives avec tous els exemple.
Tu pourra dire ce que tu en pense, là tout est de moi.

Et ça n'as strictement rien à voir avec EF ici, aucune gestion compliquer d'objet, c'est juste un gestionnaire d'affichage pour canevas voilà.
Tout est très bien commenté dans le code, j'ai fais ça bien propre.
Ce module est un module de gestion d'affichage dans un canevas.
Ce module permet de gérer l'affichage dans un canevas.

Il peut fonctionner en mode FPS (Image par secondes) ou en mode statique (Il ne se passera rien, car la procédure ne sera pas appelée).
Vous pourrez également limiter le nombre de FPS par secondes, ce qui peut être très pratique pour rendre l'affichage stable.
1 FPS = une boucle d'affichage, le nombre de FPS maximum dépend de la puissance de votre machine !
A chaque boucle d'affichage, une procédure DE VOTRE CHOIX sera appelée, c'est vous qui personnalisez l'affichage de celui-ci.

Ce module fonctionne un peu à la façon d'un écran de jeu vidéo ou à chaque boucle, l'affichage s'actualise.

Cependant ici c'est dans un canevas, pas dans un écran, ce sera donc plus lent, mais vous pourrez gérer grace à PB tous
les évènements de celui-ci et inclure ça dans votre programme facilement, c'est très simple d'utilisation et personnalisable.

Dans votre procédure de dessins, certains évènements de la souris y serront transmis automatiquement:
- Position de la souris sur le canevas.
- Largeur et Hauteur du canevas.
- Une valeur personnalisée de votre choix (Optionnel).
- Vous pourrez aussi savoir l'état des boutons de la souris (Enfoncé ou non) grace à des fonctions.
- Vous pourrez égallement savoir quel touche du clavier a été enfoncé.

Dans cette procédure de dessins, vous allez vous-même dessiner sur le canevas (A chaque boucle).
De plus, le module permet de personnaliser le mode de dessins de celui-ci:

En Mode 2D Drawing (La procédure de dessins devra uniquement utiliser des fonctions de la bibliotheque 2DDrawing).
En Mode Vector Drawing (La procédure de dessins devra uniquement utiliser des fonction de la bibliotheque VectorDrawing).

Vous pourrez même le changer en cours de fonctionnement, mais jamais les deux à la fois, c'est soit l'un soit l'autre.

Le module contient égallement, mais pas que, des fonctions pour avoir des informations sur le taux de raffraichissement de l'affichage du canevas.
Par exemple, le nombre de FPS par seconde de raffraichissement du canevas, et pleins d'autres fonctions de ce type.

Ce module pourait par exemple servir à aider à créer de petits jeux, par exemple des jeux drôles, ou des logiciels de dessins ou autre choses.
Voilà, c'est à vous de jouer comme on dit !
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Avatar de l’utilisateur
threedslider
Messages : 452
Inscription : dim. 01/juil./2018 22:38

Re: CanvasDrawingManager

Message par threedslider »

@Shadow : Salut, tu pourrais faire un exemple pour une appli de ton CanvasDrawingManager, stp ? Merci.
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

threedslider a écrit : jeu. 08/déc./2022 19:43 @Shadow : Salut, tu pourrais faire un exemple pour une appli de ton CanvasDrawingManager, stp ? Merci.
@threedslider, coucou, et bien il y à les exemple que tu peu trouver dans le dossier, il faut télécharger l'archive, tu as quelque exemples.
Jte propose de les tester :)

Si tu connais déjà tous ça, alors que veux tu que je face de plus ? :)
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Ekim
Messages : 215
Inscription : dim. 24/juin/2018 1:20

Re: CanvasDrawingManager

Message par Ekim »

Bonjours à tous,

Ça me fait tout de suite penser que j'avais développé il y a pas si longtemps un "petit moteur 2D" pour le traitement graphique (images XXXL vraiment grand format) en faisant appel aux "Threads" et résultats, j'ai été très déçu🥺 car au final je devais patienter 4 fois plus de temps la fin du traitement que la 1ère version non Threadé,
Et malgré la précision chirurgicale de mon code😢
je ne sais toujours pas pourquoi d'ailleurs 🤔
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Ekim a écrit : jeu. 29/déc./2022 13:26 Bonjours à tous,

Ça me fait tout de suite penser que j'avais développé il y a pas si longtemps un "petit moteur 2D" pour le traitement graphique (images XXXL vraiment grand format) en faisant appel aux "Threads" et résultats, j'ai été très déçu🥺 car au final je devais patienter 4 fois plus de temps la fin du traitement que la 1ère version non Threadé,
Et malgré la précision chirurgicale de mon code😢
je ne sais toujours pas pourquoi d'ailleurs 🤔
Salut, quel rapport avec mon module ?
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Ekim
Messages : 215
Inscription : dim. 24/juin/2018 1:20

Re: CanvasDrawingManager

Message par Ekim »

J'aurais peut-être dû préciser qu'il s'agissait d'une petite parenthèse pour ne pas heurter le stream😅
Avatar de l’utilisateur
plabouro472
Messages : 40
Inscription : sam. 23/juil./2022 10:17

Re: CanvasDrawingManager

Message par plabouro472 »

Salut Shadow,
J'ai trouvé ton module très intéressant mais....
Car il y a un MAIS, c'est un peut le bazar là dedans.
- Nom des commandes bien trop long.
- Il faut récupérer des constantes du module pour ensuite les réinjecter dans ce même module via une commande
Ex : GetCanvasAttributeCanvasDrawingManager(Canvas.i, #CanvasAttributeMouseOver)

j'ai eu du mal à m'y retrouver alors j'ai décidé de faire le ménage dans ta chambre.
- J'ai renommé les commande pour les rendre plus claire.
- là ou une procédure gérait plusieurs commande, plusieurs procédure gèrent une seule commande.

Dans le programme principal, on n'utilisera pas cette fonction : UseModule CanvasDrawingManager
mais plutôt cette méthode : CanvasDrawingManager::Init(#CanvasGadget)
ceci évitera d'éventuelles conflit avec des commande similaire aux autres modules et rendra le code plus clair,
on voit bien ici qu'il s’agit de la commande Init du module CanvasDrawingManager.

La liste des commande du module est simple et se passe de commentaires.
La voici :
Init ( CanvasNumber.i , DrawingMode.i = #CanvasDrawingMode2DDrawing , AutoRefrech.b = #True , Delay.i = 0 , Priority.i = 0 ) ; Remplacée par suivants
Init ( CanvasNumber.i ) ; Modifié
IsInit ( CanvasNumber.i ) ; Ajouté

SetDrawingMode ( CanvasNumber.i , DrawingMode.i ) ; Remplacée par suivants
SetMode2DDrawing ( CanvasNumber.i ) ; Ajouté
SetModeVectorDrawing ( CanvasNumber.i ) ; Ajouté

SetCallBack ( CanvasNumber.i , ProcedureDrawingCallBack.PrototypeCanvas , Value.i = 0 )

SetDelayRefhech ( CanvasNumber.i , Delay.i )
SetRefhechPriority ( CanvasNumber.i , Priority.i )
SetRefhechLimiteFPS ( CanvasNumber.i , FPS.i )

SetAutoRefrech ( CanvasNumber.i , AutoRefrech.b ) ; Remplacée par suivants
SetAutoRefrechOn ( CanvasNumber.i ) ; Ajouté
SetAutoRefrechOff ( CanvasNumber.i ) ; Ajouté

SetImage ( CanvasNumber.i , Image.i )

GetDrawingMode ( CanvasNumber.i )
GetDelayRefhech ( CanvasNumber.i )
GetRefhechPriority ( CanvasNumber.i )
GetAutoRefrech ( CanvasNumber.i )
GetTimeLoopRefhech ( CanvasNumber.i )
GetMediumTimeLoopRefhech ( CanvasNumber.i )
GetTotaleTimeLoopRefhech ( CanvasNumber.i )
GetLoopRefhech ( CanvasNumber.i )
GetFPSRefhech ( CanvasNumber.i )
GetRefhechLimiteFPS ( CanvasNumber.i )
GetTimeWaitLoopLimiteFPS ( CanvasNumber.i )
GetMinimumFPSRefhech ( CanvasNumber.i )
GetMaximumFPSRefhech ( CanvasNumber.i )

GetCanvasAttribute ( CanvasNumber.i , CanvasAttribut.i ) ; Remplacée par suivants
GetMouseX ( CanvasNumber.i ) ; Ajouté
GetMouseY ( CanvasNumber.i ) ; Ajouté
MouseIsOver ( CanvasNumber.i ) ; Ajouté
LeftMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
RightMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
MiddleMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
GetLastKeyHold ( CanvasNumber.i ) ; Ajouté
GetKeyBoardImput ( CanvasNumber.i ) ; Ajouté

GetImage ( CanvasNumber.i )

Release ( CanvasNumber.i = #CanvasDrawingManager_All ) ; Remplacée par suivants
Release (CanvasNumber.i ) ; Modifié
ReleaseAll ( ) ; Ajouté


par exemple, à la place de :
Select GetCanvasAttributeCanvasDrawingManager(Canvas.i, #CanvasAttributeKeyBoardLastKeyHold)
Case 37 ; Flèche gauche.
If PersoX.f > 10
PersoX.f - VitesseDeplacement.i
Changement.b = #True ; Pour réafficher le contenu sur le canevas.
DirectionPerso.i = 270 ; Tourne le personnage vers la gauche (270°).
EndIf

On aura :
Select CanvasDrawingManager::GetLastKeyHold( Canvas )
Case #PB_Shortcut_Left ; Flèche gauche.
If PersoX.f > 10
PersoX.f - VitesseDeplacement.i
Changement.b = #True ; Pour réafficher le contenu sur le canevas.
DirectionPerso.i = 270 ; Tourne le personnage vers la gauche (270°).
EndIf

Ton code lui, n'a pas changé, j'ai juste réorganisé ton travail pour le rendre plus simple à lire et à utiliser pour moi et les autres.

Il te reste à adapter les exemples à cette version ou garder l'ancienne, c'est toi qui vois.

Code : Tout sélectionner

 

;{ Créé par Dieppedalle David alias Shadow Storm le 12/02/2022.

; Merci à Naheulf pour m'avoir un peu aidé en me disant comment optimiser un peu la vitesse du programme.
; Merci à Micoute d'avoir corrigé les fautes d'orthographe.
; 
; Ce Module est un Module de gestion d'affichage dans un canevas.
; Ce Module permet de gérer l'affichage dans un canevas.
; 
; Il peut fonctionner en mode FPS (Image par seconde) ou en mode statique (Il ne se passera rien, car la procédure ne sera pas appelée).
; Vous pourrez également limiter le nombre de FPS par secondes, ce qui peut être très pratique pour rendre l'affichage stable.
; 1 FPS = une boucle d'affichage, le nombre de FPS maximum dépend de la puissance de votre machine !
; A chaque boucle d'affichage, une procédure DE VOTRE CHOIX sera appelée, c'est vous qui personnalisez l'affichage de votre canevas.
; 
; Ce Module fonctionne un peu à la façon d'un écran de jeu vidéo ou à chaque boucle, l'affichage s'actualise.
; 
; Cependant ici, c'est dans un canevas, pas dans un écran, ce sera donc plus lent, mais vous pourrez gérer grace à PB tous
; les évènements de celui-ci (Dans la boucle principale de votre programme) et inclure ça dans votre programme facilement, c'est très simple d'utilisation et personnalisable.
; 
; Dans votre procédure de dessins, certains évènements de la souris y serront transmis automatiquement:
; - Position de la souris sur le canevas.
; - Largeur et Hauteur du canevas.
; - Une valeur personnalisée de votre choix (Optionnel).
; - Vous pourrez aussi savoir l'état des 3 boutons standard de la souris (Enfoncé ou non) grace une des fonctions.
; - Vous pourrez égallement savoir quel touche du clavier a été enfoncé.
; 
; Dans cette procédure de dessins, vous allez vous-même dessiner sur le canevas (A chaque boucle).
; De plus, le Module permet de personnaliser le mode de dessins de celui-ci:
; 
; En Mode 2D Drawing (La procédure de dessins devra uniquement utiliser des fonctions de la bibliotheque 2DDrawing).
; En Mode Vector Drawing (La procédure de dessins devra uniquement utiliser des fonction de la bibliotheque VectorDrawing).
; 
; Vous pourrez même le changer en cours de fonctionnement, mais jamais les deux à la fois, c'est soit l'un soit l'autre.
; 
; Le Module contient également, mais pas que, des fonctions pour avoir des informations sur le taux de rafraichissement de l'affichage du canevas.
; Par exemple, le nombre de FPS par seconde de rafraichissement du canevas, et plein d'autres fonctions de ce type.

; Version actuelle: 1.12.0
; Actualisée le 21/02/2025

;}

; Message pour Option de compilation des Threads (Merci à Falsam pour l'idée).
CompilerIf Not #PB_Compiler_Thread
 CompilerError "Vous devez activer dans votre fichier de code l'option 'Activer la gestion des threads' dans les options de compilation !"
CompilerEndIf

DeclareModule CanvasDrawingManager
 ; Les lignes ci-dessous sont déplacées dans le module pour les rendre privées
 ; Il n'est pas utile d'y accéder depuis l'extèrieure
 ; #CanvasDrawingManager_All = -1
 ; #CanvasAttributeMouseX = -2 
 ; #CanvasAttributeMouseY = -3
 ; #CanvasAttributeMouseOver = -4
 ; #CanvasAttributeLeftMouseButtonHold = -5
 ; #CanvasAttributeRightMouseButtonHold = -6
 ; #CanvasAttributeMiddleMouseButtonHold = -7
 ; #CanvasAttributeKeyBoardLastKeyHold = -8
 ; #CanvasAttributeKeyBoardInput = -9
 ; #CanvasDrawingMode2DDrawing = -10
 ; #CanvasDrawingModeVectorDrawing = -11
 
 ;{ Ceci sert à créer une procédure personnalisée pour définir le dessins du canevas qui sera actualisé à chaque boucle, cette boucle est gérée par un Thread.
 ; Le nom du prototype est 'PrototypeCanvas', celui-ci contient 3 paramètres.
 ; Dans la procédure de dessins personnalisée, ce nom sera remplacé par un nom de procédure quelconque, mais devra contenir ces 3 paramètres
 ; Le nom des paramètres dans la procédure de dessins n'a aucune importance, mais les types doivent rester inchangés.
 ; Au final cela deviendra quelque chose du style: MaProcedureDessinsCanevas(NumeroCanevas.i, LargeurCanevas.i, HauteurCanevas.i)
 ; Pour pouvoir appeler cette fameuse procédure de dessins personnalisés, le programme devra donc savoir son adresse, et comment on fait ça ?:
 ; 
 ; Avec la fonction suivante: SetCallBack(CanvasNumber.i, ProcedureDrawingCallBack.PrototypeCanvas)
 ; Le paramètre 'ProcedureDrawingCallBack.PrototypeCanvas' est une variable (ProcedureDrawingCallBack) qui pointe vers le prototype (PrototypeCanvas)
 ; et contiendra donc l'adresse de cette procédure en la renseignant, par exemple comme ceci:
 ; 
 ; SetCallBack(#CanvasGadget, @MaProcedureDessinsCanevas())
 ; Le paramètre donné suivant '@MaProcedureDessinsCanevas' est l'adresse de cette fameuse procédure de dessins personnalisés pour ce canevas !
 ;}
 Prototype.i PrototypeCanvas(CanvasNumber.i, CanvasMouseX.i, CanvasMouseY.i, CanvasWidth.i, CanvasHeight.i, Value.i)
 
 ; Les commandes ont été simplifiées ( 1 ou 2 paramètres au plus )
 ; et plus facile à comprendre ( leurs nom a été raccourci pour une meilleure lisibilité )
 ;Declare.b Init ( CanvasNumber.i , DrawingMode.i = #CanvasDrawingMode2DDrawing , AutoRefrech.b = #True , Delay.i = 0 , Priority.i = 0 ) ; Remplacée par suivants
 Declare.b Init ( CanvasNumber.i ) ; Modifié
 Declare.b IsInit ( CanvasNumber.i ) ; Ajouté
 
 ;Declare.b SetDrawingMode ( CanvasNumber.i , DrawingMode.i ) ; Remplacée par suivants
 Declare.b SetMode2DDrawing ( CanvasNumber.i ) ; Ajouté
 Declare.b SetModeVectorDrawing ( CanvasNumber.i ) ; Ajouté
 
 Declare.b SetCallBack ( CanvasNumber.i , ProcedureDrawingCallBack.PrototypeCanvas , Value.i = 0 )
 
 Declare.b SetDelayRefhech ( CanvasNumber.i , Delay.i )
 Declare.b SetRefhechPriority ( CanvasNumber.i , Priority.i )
 Declare.b SetRefhechLimiteFPS ( CanvasNumber.i , FPS.i )
 
 ;Declare.b SetAutoRefrech ( CanvasNumber.i , AutoRefrech.b ) ; Remplacée par suivants
 Declare.b SetAutoRefrechOn ( CanvasNumber.i ) ; Ajouté
 Declare.b SetAutoRefrechOff ( CanvasNumber.i ) ; Ajouté
 
 Declare.b SetImage ( CanvasNumber.i , Image.i )
 
 
 Declare.i GetDrawingMode ( CanvasNumber.i )
 Declare.i GetDelayRefhech ( CanvasNumber.i )
 Declare.i GetRefhechPriority ( CanvasNumber.i )
 
 Declare.b GetAutoRefrech ( CanvasNumber.i )
 Declare.i GetTimeLoopRefhech ( CanvasNumber.i )
 Declare.f GetMediumTimeLoopRefhech ( CanvasNumber.i )
 Declare.i GetTotaleTimeLoopRefhech ( CanvasNumber.i )
 Declare.i GetLoopRefhech ( CanvasNumber.i )
 Declare.i GetFPSRefhech ( CanvasNumber.i )
 Declare.i GetRefhechLimiteFPS ( CanvasNumber.i )
 Declare.i GetTimeWaitLoopLimiteFPS ( CanvasNumber.i )
 Declare.i GetMinimumFPSRefhech ( CanvasNumber.i )
 Declare.i GetMaximumFPSRefhech ( CanvasNumber.i )
 
 ;Declare.i GetCanvasAttribute ( CanvasNumber.i , CanvasAttribut.i ) ; Remplacée par suivants
 Declare.i GetMouseX ( CanvasNumber.i ) ; Ajouté
 Declare.i GetMouseY ( CanvasNumber.i ) ; Ajouté
 Declare.a MouseIsOver ( CanvasNumber.i ) ; Ajouté
 Declare.a LeftMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
 Declare.a RightMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
 Declare.a MiddleMouseButtonIsHold ( CanvasNumber.i ) ; Ajouté
 Declare.i GetLastKeyHold ( CanvasNumber.i ) ; Ajouté
 Declare.i GetKeyBoardImput ( CanvasNumber.i ) ; Ajouté
 
 Declare.i GetImage ( CanvasNumber.i )
 
 ;Declare.b Release ( CanvasNumber.i = #CanvasDrawingManager_All ) ; Remplacée par suivants
 Declare.b Release (CanvasNumber.i ) ; Ajouté
 Declare.b ReleaseAll ( ) ; Ajouté

EndDeclareModule
Module CanvasDrawingManager
 ; Constantes privées
 ; Les constantes suivantes ne sont plus utile
 ;#CanvasDrawingManager_All = -1
 ;#CanvasAttributeMouseX = -2 
 ;#CanvasAttributeMouseY = -3
 ;#CanvasAttributeMouseOver = -4
 ;#CanvasAttributeLeftMouseButtonHold = -5
 ;#CanvasAttributeRightMouseButtonHold = -6
 ;#CanvasAttributeMiddleMouseButtonHold = -7
 ;#CanvasAttributeKeyBoardLastKeyHold = -8
 ;#CanvasAttributeKeyBoardInput = -9
 
 #CanvasDrawingMode2DDrawing = -10
 #CanvasDrawingModeVectorDrawing = -11
 
 Structure StructureCanvasDrawingManager
 CanvasInit .b ; Si le canevas est intitialisé (#True) ou non (#False).
 CanvasNumber .i ; Le numéro du canevas.
 CanvasImage .i ; L'image du canevas.
 CanvasDrawingMode .i ; Le mode de dessins, soit 2DDrawing (Par Défaut), soit VectorDrawing.
 CanvasAutoRefrech .b ; #True (1) si l'auto-rafraissement du canevas est activé, sinon #False (0).
 CanvasDrawingCallBack .PrototypeCanvas ; Adresse de la procédure pour dessiner sur le canevas.
 CanvasDrawingCallBackValue .i ; Une valeur qui sera transmise à la procédure de dessins du canevas.
 CanvasThreadNumber .i ; Le numéro du Thread du canevas.
 CanvasThreadDelay .i ; Le delai entre chaque boucle d'affichage du canevas.
 CanvasThreadPriority .i ; La priorité du thread du canevas qui gére l'affichage de celui-ci.
 CanvasTimeLoop .i ; Le temps de la boucle (Frame) actuel d'affichage du canevas.
 CanvasMediumTimeLoop .f ; Le temps moyen des boucles (Frame) d'affichage du canevas, calculé et actualisé à chaque seconde.
 CanvasTotaleTimeLoop .i ; Le temps total de toutes les boucles (Frame) d'affichage du canevas, remis à 0 à chaque seconde.
 CanvasLoop .i ; Le nombre de boucles (Frame) actuelles accomplies, remis à 0 à chaque seconde.
 CanvasFPS .i ; Le nombre de boucles (Frame) accomplies en 1 seconde, actualisé à chaque seconde.
 CanvasLimiteFPS .i ; Le nombre de boucles (Frame) maximum que devra accomplir en 1 seconde le canevas.
 CanvasTimeWaitLimiteFPS .i ; Le temps en MS qu'attent le thread dans la boucle actuelle si 'CanvasLimiteFPS.i' est actif.
 CanvasMinimumFPS .i ; Le nombre de boucles (Frame) minimum accomplies en 1 seconde, actualisé à chaque seconde.
 CanvasMaximumFPS .i ; Le nombre de boucles (Frame) maximum accomplies en 1 seconde, actualisé à chaque seconde.
 CanvasMouseX .i ; La dernière position connue X de la souris sur le canevas.
 CanvasMouseY .i ; La dernière position connue Y de la souris sur le canevas.
 CanvasMouseOver .b ; #True (1) la souris est sur le canevas, sinon #False (0).
 CanvasLeftMouseButtonHold .b ; #True (1) si le bouton gauche de la souris est enfoncé sur le canevas, sinon #False (0).
 CanvasRightMouseButtonHold .b ; #True (1) si le bouton droit de la souris est enfoncé sur le canevas, sinon #False (0).
 CanvasMiddleMouseButtonHold .b ; #True (1) si le bouton centre de la souris est enfoncé sur le canevas, sinon #False (0).
 CanvasKeyBoardLastKeyHold .i ; La dernière touche du clavier qui est actuellement pressée.
 CanvasKeyBoardImput .i ; Le dernier caractère qui à été saisi au clavier.
 EndStructure
 
 ; Map qui sert pour enregistrer les canevas.
 Global NewMap MapCanvas.StructureCanvasDrawingManager()
 
 ; Teste si le canevas est initialisé pour l'utiliser avec CanvasDrawingManager.
 ; Donne #True (1) si le canevas a été initialisé pour l'utiliser avec CanvasDrawingManager, sinon renvoie #False (0) si le canevas n'existe pas. (Cette macro est Privée au module).
 ;Macro _IsInit(CanvasNumber) ; Pour usage dans le module
 ; Bool(IsGadget(CanvasNumber.i) And MapCanvas(Str(CanvasNumber.i))\CanvasInit = #True)
 ;EndMacro
 
 ;{ Procédures privées
 
 ; La CallBack qui va enregistrer la position et l'état de la souris sur le canevas dès que celle-ci va bouger ou qu'un évènement intervient sur celui-ci
 ; (Cette procédure est Privée au Module, les autres sont publiques).
 Procedure CallBackEventCanvas()
 
 ; On récupère le numéro du canevas ou l'évènement s'est produit.
 Canvas.i = EventGadget()
 
 ; Le pointeur '*Manager' pointe sur la structure 'StructureCanvasDrawingManager' à l'adresse du numéro du canevas.
 Protected *Manager.StructureCanvasDrawingManager = @MapCanvas(Str(Canvas.i))
 
 Select EventType()
 
 Case #PB_EventType_MouseEnter ; Le curseur de la souris est entré dans le gadget.
 *Manager\CanvasMouseOver = #True
 
 Case #PB_EventType_MouseLeave ; Le curseur de la souris est sorti du gadget.
 *Manager\CanvasMouseOver = #False
 
 Case #PB_EventType_MouseMove; Le curseur de la souris a bougé.
 *Manager\CanvasMouseX = GetGadgetAttribute(Canvas.i, #PB_Canvas_MouseX)
 *Manager\CanvasMouseY = GetGadgetAttribute(Canvas.i, #PB_Canvas_MouseY)
 
 Case #PB_EventType_LeftButtonDown ; Le bouton gauche de la souris a été pressé.
 *Manager\CanvasLeftMouseButtonHold = #True
 
 Case #PB_EventType_LeftButtonUp ; Le bouton gauche de la souris a été relâché.
 *Manager\CanvasLeftMouseButtonHold = #False
 
 Case #PB_EventType_RightButtonDown ; Le bouton droit de la souris a été pressé.
 *Manager\CanvasRightMouseButtonHold = #True
 
 Case #PB_EventType_RightButtonUp ; Le bouton droit de la souris a été relâché.
 *Manager\CanvasRightMouseButtonHold = #False
 
 Case #PB_EventType_MiddleButtonDown ; Le bouton centre de la souris a été pressé.
 *Manager\CanvasMiddleMouseButtonHold = #True
 
 Case #PB_EventType_MiddleButtonUp ; Le bouton centre de la souris a été relâché.
 *Manager\CanvasMiddleMouseButtonHold = #False
 
 Case #PB_EventType_KeyDown ; Une touche du clavier a été enfoncée.
 *Manager\CanvasKeyBoardLastKeyHold = GetGadgetAttribute(Canvas.i, #PB_Canvas_Key)
 
 Case #PB_EventType_KeyUp ; Une touche du clavier a été relâchée.
 *Manager\CanvasKeyBoardLastKeyHold = 0
 *Manager\CanvasKeyBoardImput = 0
 
 Case #PB_EventType_Input ; Un caractère a été entré avec le clavier.
 *Manager\CanvasKeyBoardImput = GetGadgetAttribute(Canvas.i, #PB_Canvas_Input)
 
 Case #PB_EventType_Resize
 ; Canvas.i
 
 Default
 ; Debug EventType()
 
 EndSelect
 
 EndProcedure
 ; Le Thread qui va gérer l'affichage sur le canevas. 
 ; (Cette procédure est Privée au Module, les autres sont publiques).
 Procedure ThreadCanvas(CanvasNumber.i)
 
 ; Le pointeur '*Manager' pointe sur la structure 'StructureCanvasDrawingManager' à l'adresse du numéro du canevas.
 Protected *Manager.StructureCanvasDrawingManager = @MapCanvas(Str(CanvasNumber.i))
 
 ; Appelle une procédure de gestion des évènements du canevas.
 BindGadgetEvent(CanvasNumber.i, @CallBackEventCanvas(), #PB_All)
 
 Repeat
 
 ; Si l'auto-rafraichissement du canevas est activé.
 If *Manager\CanvasAutoRefrech = #True
 
 ; Sauvegarde le temps actuel.
 TimeStart.i = ElapsedMilliseconds()
 
 ; Si le mode de dessins du canevas est 2DDrawing.
 If *Manager\CanvasDrawingMode = #CanvasDrawingMode2DDrawing
 
 ; Si on peut dessiner sur le canevas.
 If StartDrawing(CanvasOutput(CanvasNumber.i))
 
 ; Si le canevas à une procédure de dessins.
 If *Manager\CanvasDrawingCallBack <> #Null ; Si l'adresse de la procédure est différente de 0.
 
 ; Appelle la procédure de dessins du canevas avec les paramètres demandés, depuis son adresse, définie par l'utilisateur, voir la fonction 'SetCallBack'.
 ; Ceci utilise le prototype 'PrototypeCanvas', voir dans DeclareModule.
 *Manager\CanvasDrawingCallBack(CanvasNumber.i, *Manager\CanvasMouseX, *Manager\CanvasMouseY, GadgetWidth(CanvasNumber.i), GadgetHeight(CanvasNumber.i), *Manager\CanvasDrawingCallBackValue)
 
 EndIf
 
 StopDrawing()
 
 EndIf
 
 ; Si le mode de dessins du canevas est VectorDrawing ou n'importe quoi d'autre.
 Else ; #CanvasDrawingModeVectorDrawing.
 
 ; Si on peut dessiner sur le canevas.
 If StartVectorDrawing(CanvasVectorOutput(CanvasNumber.i))
 
 ; Si le canevas à une procédure de dessins.
 If *Manager\CanvasDrawingCallBack <> #Null ; Si l'adresse de la procédure est différente de 0.
 
 ; Appelle la procédure de dessins du canevas avec les paramètres demandés, depuis son adresse, définie par l'utilisateur, voir la fonction 'SetCallBack'.
 ; Ceci utilise le prototype 'PrototypeCanvas', voir dans DeclareModule.
 *Manager\CanvasDrawingCallBack(CanvasNumber.i, *Manager\CanvasMouseX, *Manager\CanvasMouseY, GadgetWidth(CanvasNumber.i), GadgetHeight(CanvasNumber.i), *Manager\CanvasDrawingCallBackValue)
 EndIf
 
 StopVectorDrawing()
 
 EndIf
 
 EndIf
 
 ; Attend le temps défini dans la procédure d'initialisation du canevas ou dans la procédure SetDelayRefhech().
 Delay(*Manager\CanvasThreadDelay)
 
 
 ; Si la limite de FPS est supérieure à 0 et qu'il y à un temps de calculé (Les calculs sont réalisés à partir de la boucle précédante).
 If *Manager\CanvasLimiteFPS > 0 And *Manager\CanvasTimeLoop > 0
 
 ; Calcule le nombre de frames actuelles potentielles.
 ; 1 seconde = 1000 MS, 1000 est divisé par le temps de la dernière boucle pour estimer le nombre de frame par seconde et ainsi ajuster les FPS en temps réel.
 CalculeFrameSeconde.f = 1000 / *Manager\CanvasTimeLoop
 
 ; Si le nombre de FPS potentiel calculé est supérieur au nombre de FPS limite.
 If CalculeFrameSeconde.f > *Manager\CanvasLimiteFPS
 *Manager\CanvasTimeWaitLimiteFPS + 1 ; Ajoute 1 MS de temps d'attente.
 
 ; Sinon si le nombre de FPS potentielles calculées est inférieur au nombre de FPS limite et que le temps d'attente est supérieur à 0.
 ElseIf (CalculeFrameSeconde.f < *Manager\CanvasLimiteFPS) And *Manager\CanvasTimeWaitLimiteFPS > 0
 *Manager\CanvasTimeWaitLimiteFPS - 1 ; Enlève 1 MS de temps d'attente.
 
 EndIf
 
 If *Manager\CanvasTimeWaitLimiteFPS < 0
 *Manager\CanvasTimeWaitLimiteFPS = 0
 EndIf
 
 ; Attent ce nombre de MS avant de continuer.
 Delay(*Manager\CanvasTimeWaitLimiteFPS)
 
 EndIf
 
 ; Sauvegarde le temps actuel.
 TimeEnd.i = ElapsedMilliseconds()
 
 ; Le temps de cette boucle.
 *Manager\CanvasTimeLoop = (TimeEnd.i - TimeStart.i)
 
 ; Le temps total de toutes les boucles.
 *Manager\CanvasTotaleTimeLoop + *Manager\CanvasTimeLoop
 
 ; Le nombre de boucles actuelles.
 *Manager\CanvasLoop + 1
 
 ; Si une seconde s'est écoulée.
 If *Manager\CanvasTotaleTimeLoop >= 1000
 
 ; Le nombre de boucles faites en 1 seconde.
 *Manager\CanvasFPS = *Manager\CanvasLoop
 
 If *Manager\CanvasMinimumFPS > 0 And *Manager\CanvasLoop < *Manager\CanvasMinimumFPS
 ; Le nombre de boucles minimum faites en 1 seconde.
 *Manager\CanvasMinimumFPS = *Manager\CanvasLoop
 ElseIf *Manager\CanvasMinimumFPS = 0
 ; Le nombre de boucles minimum faites en 1 seconde.
 *Manager\CanvasMinimumFPS = *Manager\CanvasLoop
 EndIf
 
 If *Manager\CanvasLoop > *Manager\CanvasMaximumFPS
 ; Le nombre de boucles maximum faites en 1 seconde.
 *Manager\CanvasMaximumFPS = *Manager\CanvasLoop
 EndIf
 
 ; Le temps moyen de toutes les boucles sur une seconde, actualisé à chaque seconde.
 *Manager\CanvasMediumTimeLoop = *Manager\CanvasTotaleTimeLoop / *Manager\CanvasLoop
 
 ; Le temps total de toutes les boucles, remis à 0.
 *Manager\CanvasTotaleTimeLoop = 0
 
 ; Le nombre de boucle actuel est remis à 0.
 *Manager\CanvasLoop = 0
 
 EndIf
 
 Else ; Si l'auto-rafraichissement du canevas est désactivé, attendra indéfiniment 25 MS, à moins que celui-ci ne soit réactivé.
 Delay(25)
 
 EndIf
 
 ForEver
 
 EndProcedure
 ;}
 
 
 ;{ Procédures publiques
 
 ;{ Initialise la gestion du canevas pour gérer l'affichage automatiquement de celui-ci.
 ; CanvasNumber.i = Le numéro du canevas.
 ; DrawingMode.i = #CanvasDrawingMode2DDrawing pour utiliser le mode de dessins 2DDrawing dans la procédure personnalisé de dessins du canevas.
 ;  #CanvasDrawingModeVectorDrawing pour utiliser le mode de dessins VectorDrawing dans la procédure personnalisé de dessins du canevas.
 ; AutoRefrech.b = #True (1) pour actualiser l'affichage automatiquement du canevas en mode FPS, 1 FPS = 1 appel de la procédure de dessins
 ;  sinon #False (0) = l'affichage du canevas ne sera pas actualisé et la procédure de dessins du canevas ne sera pas appelé.
 ; Delay.i = le délai d'attente dans le Thread qui gére l'affichage du canevas (Entre chaque boucle de l'affichage du canevas), 0 = pas d'attente = rapidité et utilisation du processeur (1 Thread) au maximum.
 ; Priority.i = La priorité du Thread qui gére l'affichage du canevas, 0 = Normale, entre 1 et 31, plus le nombre est grand et plus la priorité sera grande, 32 = temps réel.
 ;
 ; Renvoie #True (1) si le canevas à été initialisé, sinon renvoie #False (0) si le canevas ou l'image n'existe pas ou si celui-ci est déjà initialisé.
 ;}
 Procedure.b Init(CanvasNumber.i ) ; , DrawingMode.i = #CanvasDrawingMode2DDrawing, AutoRefrech.b = #True, Delay.i = 0, Priority.i = 0)
 
 ; Cherche si l'élément est présent dans la map et récupère son adresse s'il existe.
 ; S'il n'existe pas (Car n'a pas encore été ajouté) l'adresse vaut #Null = #False = 0 
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 
 ; Si l'élément n'existe pas
 If Not *Manager
 ; Crée l'élément et récupére son adresse.
 *Manager = AddMapElement(MapCanvas(), Str(CanvasNumber.i), #PB_Map_NoElementCheck)
 EndIf
 
 If IsGadget(CanvasNumber.i) And *Manager\CanvasInit = #False
 
 *Manager\CanvasNumber = CanvasNumber.i
 
 ;If Delay.i < 0
 Delay.i = 0
 ;EndIf
 
 Thread.i = CreateThread(@ThreadCanvas(), CanvasNumber.i)
 
 If IsThread(Thread.i)
 
 ;If Priority.i < 0
 Priority.i = 0
 ;ElseIf Priority.i > 32
 ; Priority.i = 32
 ;EndIf
 
 ;If DrawingMode.i <> #CanvasDrawingMode2DDrawing And DrawingMode.i <> #CanvasDrawingModeVectorDrawing
 DrawingMode.i = #CanvasDrawingMode2DDrawing
 ;EndIf
 
 ThreadPriority(Thread.i, Priority.i)
 
 *Manager\CanvasThreadNumber = Thread.i
 *Manager\CanvasThreadDelay.i = Delay.i
 *Manager\CanvasThreadPriority = Priority.i
 *Manager\CanvasInit = #True
 *Manager\CanvasAutoRefrech = AutoRefrech.b
 *Manager\CanvasDrawingMode = DrawingMode.i
 
 ProcedureReturn #True
 
 EndIf
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Teste si le canevas est initialisé pour l'utiliser avec CanvasDrawingManager.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Renvoie #True (1) si le canevas existe et est initialisé pour l'utiliser avec CanvasDrawingManager, sinon
 ; renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 Procedure.b IsInit(CanvasNumber.i)
 ;ProcedureReturn _IsInit(CanvasNumber) Pourquoi passer par une MACRO ?
 ProcedureReturn Bool(IsGadget(CanvasNumber.i) And MapCanvas(Str(CanvasNumber.i))\CanvasInit = #True)
 EndProcedure
 
 
 ;{ Change le mode de dessins du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; DrawingMode.i = Le mode de dessins de la procédure de dessins personnalisé du canevas:
 ;  #CanvasDrawingMode2DDrawing = Pour utiliser des fonctions de type 2DDrawing dans la procédure de dessins personnaliser du canevas.
 ;  #CanvasDrawingModeVectorDrawing = Pour utiliser des fonctions de type VectorDrawing dans la procédure de dessins personnaliser du canevas.
 ; 
 ; Renvoie #True (1) si le mode de dessins du canevas a été Changé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 ;{ Procedure.b SetDrawingMode(CanvasNumber.i, DrawingMode.i) ; Remplacée par suivants
 ; 
 ; If IsInit(CanvasNumber.i)
 ; If DrawingMode.i <> #CanvasDrawingMode2DDrawing And DrawingMode.i <> #CanvasDrawingModeVectorDrawing
 ; DrawingMode.i = #CanvasDrawingMode2DDrawing
 ; EndIf
 ; MapCanvas(Str(CanvasNumber.i))\CanvasDrawingMode = DrawingMode.i
 ; ProcedureReturn #True
 ; EndIf
 ; 
 ; ProcedureReturn #False
 ; 
 ; EndProcedure
 ;}
 Procedure.b SetMode2DDrawing ( CanvasNumber.i ) ; Ajouté
 If IsInit(CanvasNumber.i)
 MapCanvas(Str(CanvasNumber.i))\CanvasDrawingMode = #CanvasDrawingMode2DDrawing
 ProcedureReturn #True
 EndIf
 
 ProcedureReturn #False
 EndProcedure
 Procedure.b SetModeVectorDrawing ( CanvasNumber.i ) ; Ajouté
 If IsInit(CanvasNumber.i)
 MapCanvas(Str(CanvasNumber.i))\CanvasDrawingMode = #CanvasDrawingModeVectorDrawing
 ProcedureReturn #True
 EndIf
 
 ProcedureReturn #False
 EndProcedure
 ;{ Définit la procédure de dessins du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; ProcedureDrawingCallBack.PrototypeCanvas = Adresse de la procédure de dessins du canevas > '@' suivie du nom de la procédure de dessins personnalisé pour ce canevas, Exemple: @MaProcedureDessinsCanevas().
 ; Value.i = Une valeur quelconque envoyée à la procédure de dessins du canevas, Optionnel.
 ; Renvoie #True (1) si la procédure de dessins du canevas a été définie, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 Procedure.b SetCallBack(CanvasNumber.i, ProcedureDrawingCallBack.PrototypeCanvas, Value.i = 0)
 
 If IsInit(CanvasNumber.i)
 MapCanvas(Str(CanvasNumber.i))\CanvasDrawingCallBack = ProcedureDrawingCallBack
 MapCanvas(Str(CanvasNumber.i))\CanvasDrawingCallBackValue = Value.i
 ProcedureReturn #True
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 
 
 ;{ Change le délai de rafraichissement du thread qui gére l'affichage du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Delay.i = Le délai d'attente entre chaque boucle d'affichage du canevas en MS.
 ; Renvoie #True (1) si le delai de rafraichissement du canevas a été changé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 Procedure.b SetDelayRefhech(CanvasNumber.i, Delay.i)
 
 If IsInit(CanvasNumber.i)
 
 If Delay.i < 0
 Delay.i = 0
 EndIf
 
 MapCanvas(Str(CanvasNumber.i))\CanvasThreadDelay = Delay.i
 ProcedureReturn #True
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Change la priorité du thread qui gére l'affichage du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Priority.i = La priorité du Thread, 0 = Normale, 1 à 31, plus le nombre est haut, plus la priorité du Thread sera importante, 32 = temps réel.
 ; Renvoie #True (1) si la priorité de l'affichage du canevas a été changée, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 Procedure.b SetRefhechPriority(CanvasNumber.i, Priority.i)
 
 If IsInit(CanvasNumber.i)
 
 If Priority.i < 0
 Priority.i = 0
 ElseIf Priority.i > 32
 Priority.i = 32
 EndIf
 
 MapCanvas(Str(CanvasNumber.i))\CanvasThreadPriority = Priority.i
 ProcedureReturn #True
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Active ou désactive l'auto-rafraissement de l'affichage du canevas. 
 ; CanvasNumber.i = Le numéro du canevas.
 ; AutoRefrech.b = #True pour activer l'auto-rafraissement de l'affichage du canevas, #False pour le désactivé.
 ; Renvoie #True (1) si l'auto-rafraissement de l'affichage du canevas a été changé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 ;{ Procedure.b SetAutoRefrech(CanvasNumber.i, AutoRefrech.b) ; Remplacée par suivants
 ; 
 ; If IsCanvasDrawingManager(CanvasNumber.i)
 ; 
 ; MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasAutoRefrech = AutoRefrech.b
 ; ProcedureReturn #True
 ; 
 ; EndIf
 ; 
 ; ProcedureReturn #False
 ; 
 ; EndProcedure
 ;}
 Procedure.b SetAutoRefrechOn(CanvasNumber.i) ; Ajouté
 
 If IsInit(CanvasNumber.i)
 
 MapCanvas(Str(CanvasNumber.i))\CanvasAutoRefrech = 1
 ProcedureReturn #True
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 Procedure.b SetAutoRefrechOff(CanvasNumber.i) ; Ajouté
 
 If IsInit(CanvasNumber.i)
 
 MapCanvas(Str(CanvasNumber.i))\CanvasAutoRefrech = 0
 ProcedureReturn #True
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Définit le nombre de FPS (Frame par seconde) de rafraichissement maximum du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; FPS.i = Le nombre de FPS maximum, Minimum = 5, attention plus ce nombre est grand et moins la limitation risque d'être précise, le calcule est fait à chaque Frame.
 ; Renvoie #True (1) si le nombre de FPS du canevas a été changé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ;}
 Procedure.b SetRefhechLimiteFPS(CanvasNumber.i, FPS.i)
 
 If IsInit(CanvasNumber.i)
 
 If FPS.i <= 5
 FPS.i = 5
 EndIf
 
 MapCanvas(Str(CanvasNumber.i))\CanvasLimiteFPS = FPS.i
 ProcedureReturn #True
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Change l'image affiché sur le canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Image.i = L'image à afficher sur le canevas.
 ; Renvoie #True (1) si l'image du canevas a été changé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé ou si l'image n'est pas initialisé.
 ;}
 Procedure.b SetImage(CanvasNumber.i, Image.i)
 
 If IsInit(CanvasNumber.i)
 
 If IsImage(Image.i) And StartDrawing(CanvasOutput(CanvasNumber.i))
 DrawImage(ImageID(Image.i), 0, 0)
 StopDrawing()
 ProcedureReturn #True
 EndIf
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 
 
 
 ; Renvoie le mode de dessins du canevas: #CanvasDrawingMode2DDrawing ou #CanvasDrawingModeVectorDrawing, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetDrawingMode(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasDrawingMode
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le délai d'actualisation du thread qui gére l'affichage du canevas, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetDelayRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasThreadDelay
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie la priorité du thread qui gére l'affichage du canevas, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetRefhechPriority(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasThreadPriority
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 
 
 ;{ Renvoie l'état de l'auto-rafraissement de l'affichage du canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Renvoie #True (1) si l'auto-rafraissement de l'affichage du canevas est activé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé ou si l'auto rafraissement de l'affichage du canevas est désactivé.
 ;}
 Procedure.b GetAutoRefrech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasAutoRefrech
 
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le délai d'actualisation de la boucle actuelle du canevas, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetTimeLoopRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasTimeLoop
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le délai d'actualisation moyen de toutes les boucles du canevas sur une seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.f GetMediumTimeLoopRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasMediumTimeLoop
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le délai d'actualisation total actuel de toutes les boucles effectuées du canevas, pour une seule seconde maximum, remis à 0 à chaque seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetTotaleTimeLoopRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasTotaleTimeLoop
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le nombre de boucles actuelles effectuées du canevas, pour une seule seconde maximum, remis à 0 à chaque seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetLoopRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasLoop
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le nombre de boucles (Frame) qu'effectue le canevas par seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetFPSRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasFPS
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie la limite de FPS du canevas, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetRefhechLimiteFPS(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasLimiteFPS
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le temps d'attente de la boucle actuelle pour correspondre à la limite de FPS du canevas, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetTimeWaitLoopLimiteFPS(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasTimeWaitLimiteFPS
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le nombre de boucles (Frame) minimum accomplies en 1 seconde, actualisé à chaque seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetMinimumFPSRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasMinimumFPS
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ; Renvoie le nombre de boucles (Frame) maximum accomplies en 1 seconde, actualisé à chaque seconde, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé.
 ; CanvasNumber.i = Le numéro du canevas.
 Procedure.i GetMaximumFPSRefhech(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 ProcedureReturn MapCanvas(Str(CanvasNumber.i))\CanvasMaximumFPS
 EndIf
 
 ProcedureReturn #False
 
 EndProcedure
 ;{ Renvoie l'état de la souris sur le canevas suivant l'attribut demandé, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé ou si l'attribut demandé n'existe pas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; MouseState:
 ; #CanvasAttributeMouseX = La dernière position connue X de la souris sur le canevas.
 ; #CanvasAttributeMouseY = La dernière position connue Y de la souris sur le canevas.
 ; #CanvasAttributeMouseOver = #True (1) la souris est sur le canevas, sinon #False.
 ; #CanvasAttributeLeftMouseButtonHold = #True (1) si le bouton gauche de la souris est enfoncé sur le canevas, sinon #False (0).
 ; #CanvasAttributeRightMouseButtonHold = #True (1) si le bouton droit de la souris est enfoncé sur le canevas, sinon #False (0).
 ; #CanvasAttributeMiddleMouseButtonHold = #True (1) si le bouton centre de la souris est enfoncé sur le canevas, sinon #False (0).
 ;}
 
 ;{ Procedure.i GetCanvasAttribute(CanvasNumber.i, CanvasAttribut.i) ; Remplacée par suivants
 ; 
 ; If IsInit(CanvasNumber.i)
 ; 
 ; ; Cherche si l'élément est présent dans la map et récupère son adresse s'il existe.
 ; ; S'il n'existe pas (Car n'a pas encore été ajouté) l'adresse vaut #Null = #False = 0 
 ; Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 ; 
 ; If *Manager
 ; 
 ; Select CanvasAttribut.i
 ; 
 ; Case #CanvasAttributeMouseX ; = -2 
 ; ProcedureReturn *Manager\CanvasMouseX
 ; 
 ; Case #CanvasAttributeMouseY ; = -3
 ; ProcedureReturn *Manager\CanvasMouseY
 ; 
 ; Case #CanvasAttributeMouseOver ; = -4
 ; ProcedureReturn *Manager\CanvasMouseOver
 ; 
 ; Case #CanvasAttributeLeftMouseButtonHold ; = -5
 ; ProcedureReturn *Manager\CanvasLeftMouseButtonHold
 ; 
 ; Case #CanvasAttributeRightMouseButtonHold ; = -6
 ; ProcedureReturn *Manager\CanvasRightMouseButtonHold
 ; 
 ; Case #CanvasAttributeMiddleMouseButtonHold ; = -7
 ; ProcedureReturn *Manager\CanvasMiddleMouseButtonHold
 ; 
 ; Case #CanvasAttributeKeyBoardLastKeyHold ; = -8
 ; ProcedureReturn *Manager\CanvasKeyBoardLastKeyHold
 ; 
 ; Case #CanvasAttributeKeyBoardInput ; = -9
 ; ProcedureReturn *Manager\CanvasKeyBoardImput
 ; 
 ; EndSelect
 ; 
 ; EndIf
 ; 
 ; EndIf
 ; 
 ; ProcedureReturn #False
 ; 
 ; EndProcedure
 ;}
 Procedure.i GetMouseX(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasMouseX
 EndIf
 EndProcedure
 Procedure.i GetMouseY(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasMouseY
 EndIf
 EndProcedure
 Procedure.a MouseIsOver(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasMouseOver
 EndIf
 EndProcedure
 Procedure.a LeftMouseButtonIsHold(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasLeftMouseButtonHold
 EndIf
 EndProcedure
 Procedure.a RightMouseButtonIsHold(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasRightMouseButtonHold
 EndIf
 EndProcedure
 Procedure.a MiddleMouseButtonIsHold(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasMiddleMouseButtonHold
 EndIf
 EndProcedure
 Procedure.i GetLastKeyHold(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasKeyBoardLastKeyHold
 EndIf
 EndProcedure
 Procedure.i GetKeyBoardImput(CanvasNumber.i) ; Ajouté
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 If *Manager
 ProcedureReturn *Manager\CanvasKeyBoardImput
 EndIf
 EndProcedure
 
 
 
 
 ;{ Crée et Renvoie l'image du canevas à cet instant ou la fonction est appelée, c'est comme une impression écran, mais pour le canevas.
 ; CanvasNumber.i = Le numéro du canevas.
 ; Renvoie le numéro de l'image qui vient d'être créée, sinon renvoie #False (0) si le canevas n'existe pas ou si celui-ci n'est pas initialisé ou si la création de l'image a échoué.
 ;}
 Procedure.i GetImage(CanvasNumber.i)
 
 If IsInit(CanvasNumber.i)
 
 ; Cherche si l'élément est présent dans la map et récupère son adresse s'il existe.
 ; S'il n'existe pas (Car n'a pas encore été ajouté) l'adresse vaut #Null = #False = 0 
 Protected *Manager.StructureCanvasDrawingManager = FindMapElement(MapCanvas(), Str(CanvasNumber.i))
 
 ; Si il y a déjà une image.
 If IsImage(*Manager\CanvasImage)
 FreeImage(*Manager\CanvasImage) ; Supprime l'image.
 EndIf
 
 ; Crée une image vide de la taille du canevas.
 *Manager\CanvasImage = CreateImage(#PB_Any, GadgetWidth(CanvasNumber.i), GadgetHeight(CanvasNumber.i))
 
 ; Si l'image est créée.
 If IsImage(*Manager\CanvasImage)
 If StartDrawing(ImageOutput(*Manager\CanvasImage)) ; Si on peut dessiner sur cette image.
 DrawImage(GetGadgetAttribute(CanvasNumber.i, #PB_Canvas_Image), 0, 0) ; Dessine l'image du canevas sur l'image créée précédément.
 StopDrawing()
 ProcedureReturn *Manager\CanvasImage
 EndIf
 EndIf
 
 EndIf
 ProcedureReturn #False
 EndProcedure
 ;{ Libère le thread du canevas indiqué ou tous les threads créés de tous les canevas, très important, à mettre AVANT de libérer un canevas et quand le programme est terminé.
 ; NOTE: Si vous libèrez un canevas avant de libérer le thread qui lui est associé, alors le programme plantera.
 ; CanvasNumber.i = Le numéro du canevas ou #CanvasDrawingManager_All pour tous.
 ; Renvoie #True (1) si le ou les threads ont été liberés, sinon renvoi #False (0).
 ;}
 ;{ Procedure.b ReleaseCanvasDrawingManager(CanvasNumber.i = #CanvasDrawingManager_All) ; Remplacée par suivants
 ; 
 ; If CanvasNumber.i = #CanvasDrawingManager_All ; = -1
 ; 
 ; ForEach MapCanvasDrawingManager()
 ; 
 ; If IsThread(MapCanvasDrawingManager(MapKey(MapCanvasDrawingManager()))\CanvasThreadNumber)
 ; KillThread(MapCanvasDrawingManager(MapKey(MapCanvasDrawingManager()))\CanvasThreadNumber)
 ; EndIf
 ; 
 ; Next
 ; 
 ; Else
 ; 
 ; If IsThread(MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasThreadNumber)
 ; KillThread(MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasThreadNumber)
 ; Else
 ; ProcedureReturn #False
 ; EndIf
 ; 
 ; EndIf
 ; 
 ; ProcedureReturn #True
 ; 
 ; EndProcedure
 ;}
 Procedure.b Release(CanvasNumber.i ) ; Ajouté
 If IsThread(MapCanvas(Str(CanvasNumber.i))\CanvasThreadNumber)
 KillThread(MapCanvas(Str(CanvasNumber.i))\CanvasThreadNumber)
 Else
 ProcedureReturn #False
 EndIf
 ProcedureReturn #True
 EndProcedure
 Procedure.b ReleaseAll( ) ; Ajouté
 ForEach MapCanvas()
 If IsThread ( MapCanvas( MapKey( MapCanvas( )))\CanvasThreadNumber )
 KillThread ( MapCanvas( MapKey( MapCanvas( )))\CanvasThreadNumber )
 EndIf
 Next
 ProcedureReturn #True
 EndProcedure
 ;}
 
EndModule




; Partie créée par Amitris_de le 10/12/2021.
; Traduit et modifié par Shadow (Dieppedalle David).

Enumeration ErrorHandler
 #ErrorHandler_Window
 #ErrorHandler_Text
 #ErrorHandler_String
 #ErrorHandler_ExitBtn
 #ErrorHandler_ClipBoardBtn
EndEnumeration 

; Procédure de gestion de Bugs.
Procedure ErrorHandler() 
 
 Protected ErrorMessage$, Event_ID
 
 Select OSVersion()
 
 Case #PB_OS_Windows_8_1
 ErrorMessage$ + "Windows: 8.1" + #CRLF$
 
 Case #PB_OS_Windows_8
 ErrorMessage$ + "Windows: 8" + #CRLF$
 
 Case #PB_OS_Windows_XP
 ErrorMessage$ + "Windows: XP" + #CRLF$
 
 Case #PB_OS_Windows_Vista
 ErrorMessage$ + "Windows: Vista" + #CRLF$
 
 Case #PB_OS_Windows_7
 ErrorMessage$ + "Windows: 7" + #CRLF$
 
 Case #PB_OS_Windows_2000 
 ErrorMessage$ + "Windows: 2000" + #CRLF$
 
 Case #PB_OS_Windows_95
 ErrorMessage$ + "Windows: 95" + #CRLF$
 
 Case #PB_OS_Windows_98 
 ErrorMessage$ + "Windows: 98" + #CRLF$
 
 Case #PB_OS_Windows_Future 
 ErrorMessage$ + "Windows: Future" + #CRLF$
 
 Case #PB_OS_Windows_ME 
 ErrorMessage$ + "Windows: ME" + #CRLF$
 
 Case #PB_OS_Windows_NT3_51 
 ErrorMessage$ + "Windows: NT3_51" + #CRLF$
 
 Case #PB_OS_Windows_NT_4 
 ErrorMessage$ + "Windows: NT_4" + #CRLF$
 
 Case #PB_OS_Windows_Server_2003 
 ErrorMessage$ + "Windows: Server_2003" + #CRLF$
 
 Case #PB_OS_Windows_Server_2008 
 ErrorMessage$ + "Windows: Server_2008" + #CRLF$
 
 Case #PB_OS_Windows_10 
 ErrorMessage$ + "Windows: 10" + #CRLF$
 
 EndSelect 
 
 ErrorMessage$ + "Message d'erreur: " + ErrorMessage() + #CRLF$
 
 Select ErrorCode()
 
 Case #PB_OnError_InvalidMemory ; Lecture ou écriture dans une zone protégée.
 ErrorMessage$ + "Lecture ou écriture dans une zone mémoire protégée - " + "Adresse mémoire cible: " + Str(ErrorTargetAddress()) + #CRLF$
 
 Case #PB_OnError_Floatingpoint ; Erreur de calcul flottant.
 ErrorMessage$ + "Erreur de calcul flottant." + #CRLF$
 
 Case #PB_OnError_Breakpoint ; Point d'arrêt débogueur atteint (autres que ceux du PureBasic.
 ErrorMessage$ + "Point d'arrêt du débogueur atteint." + #CRLF$
 
 Case #PB_OnError_IllegalInstruction ; Exécution d'une instruction invalide.
 ErrorMessage$ + "Instruction rencontrée invalide." + #CRLF$
 
 Case #PB_OnError_PriviledgedInstruction ; Exécution d'une instruction privilégiée (system-) non autorisée.
 ErrorMessage$ + "Instruction rencontrée privilégiée système non autorisée." + #CRLF$
 
 Case #PB_OnError_DivideByZero ; Division par zéro (Windows seulement).
 ErrorMessage$ + "Division par zéro." + #CRLF$
 
 Default
 ErrorMessage$ + "Code d'erreur inconnue: " + ErrorCode() + #CRLF$
 
 EndSelect
 
 ErrorMessage$ + "Ligne Code Source: " + Str(ErrorLine()) + #CRLF$
 ErrorMessage$ + "Fichier Code Source: " + GetFilePart(ErrorFile()) 
 
 If OpenWindow(#ErrorHandler_Window, 0, 0, 500, 220, "Une erreur à été rencontrée !", #PB_Window_ScreenCentered)
 
 TextGadget(#ErrorHandler_Text, 10, 10, 400, 30, "Veuillez envoyer ces informations au développeur.")
 StringGadget(#ErrorHandler_String, 10, 30, 480, 140, ErrorMessage$, #ES_MULTILINE | #WS_VSCROLL)
 ButtonGadget(#ErrorHandler_ExitBtn, 415, 180, 75, 30, "Quitter")
 ButtonGadget(#ErrorHandler_ClipBoardBtn, 10, 180, 175, 30, "Copier dans le Presse Papier")
 
 Repeat 
 
 Event_ID = WaitWindowEvent()
 
 If Event_ID = #PB_Event_Gadget
 
 Select EventGadget() 
 
 Case #ErrorHandler_ExitBtn
 End
 
 Case #ErrorHandler_ClipBoardBtn 
 SetClipboardText(ErrorMessage$)
 End
 
 EndSelect
 
 EndIf 
 
 Until Event_ID = #PB_Event_CloseWindow
 
 EndIf 
 
 End
 
EndProcedure

; Si une erreur a été rencontrée, appelle la procédure ErrorHandler().
OnErrorCall(@ErrorHandler()) 
Shadow
Messages : 1413
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

plabouro472 a écrit : ven. 21/févr./2025 17:38 Salut Shadow,
J'ai trouvé ton module très intéressant mais....
Salutation plabouro472 :)

Ah, oui, je comprends, c'est vraie que les fonction son un peu longues j'avoue :wink:
Ce qui m'intéresserais de savoir c'est pourquoi tu trouves mon module très intéressant ?
Hésite pas à dire ce que tu aime, ce que tu n'aime pas aussi (Hormis le bordel dans ma chambre :lol: :mrgreen: )

Tu peu jeter aussi un coup d'œil à un autre module qui à été entièrement réaliser par un très bon codeur (Pas moi, je suis nul).
Editors Factory, à ma demande, jte conseille le forum anglais car ya plus de chose là bas.

Tu pourra aussi me dire si tu comprends se que c'est et si ça te plais.
Au plaisir de te lire et merci à toi :)
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
Répondre