CanvasDrawingManager

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

CanvasDrawingManager

Message par Shadow »

Salutation,

J'ai créer un code pour pouvoir facilement gérer l'affichage dans un canevas.

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 grâce à 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 seront 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) grâce à des fonctions.
- Vous pourrez également 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 2DDrawing (La procédure de dessins devra uniquement utiliser des fonctions de la bibliothèque 2DDrawing).
En Mode VectorDrawing (La procédure de dessins devra uniquement utiliser des fonction de la bibliothèque 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 pleins d'autres fonctions de ce type.

Ce module pourrait 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 !

Le dossier complet ici avec 9 exemples d'utilisation:
https://drive.google.com/file/d/1eqFfMV ... share_link

; Le Module ici:

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.
; 
; Version actuelle: 1.12.0

;}

; 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
  
  #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 'PrototypeCanvasDrawingCallBack', 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: SetCallBackCanvasDrawingManager(CanvasNumber.i, ProcedureDrawingCallBack.PrototypeCanvasDrawingCallBack)
  ; Le paramètre 'ProcedureDrawingCallBack.PrototypeCanvasDrawingCallBack' est une variable (ProcedureDrawingCallBack) qui pointe vers le prototype (PrototypeCanvasDrawingCallBack)
  ; et contiendra donc l'adresse de cette procédure en la renseignant, par exemple comme ceci:
  ; 
  ; SetCallBackCanvasDrawingManager(#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 PrototypeCanvasDrawingCallBack(CanvasNumber.i, CanvasMouseX.i, CanvasMouseY.i, CanvasWidth.i, CanvasHeight.i, Value.i)
  
  Declare.b InitCanvasDrawingManager(CanvasNumber.i, DrawingMode.i = #CanvasDrawingMode2DDrawing, AutoRefrech.b = #True, Delay.i = 0, Priority.i = 0)
  Declare.b IsCanvasDrawingManager(CanvasNumber.i)
  
  Declare.b SetDrawingModeCanvasDrawingManager(CanvasNumber.i, DrawingMode.i)
  Declare.b SetCallBackCanvasDrawingManager(CanvasNumber.i, ProcedureDrawingCallBack.PrototypeCanvasDrawingCallBack, Value.i = 0)
  
  Declare.b SetDelayRefhechCanvasDrawingManager(CanvasNumber.i, Delay.i)
  Declare.b SetRefhechPriorityCanvasDrawingManager(CanvasNumber.i, Priority.i)
  Declare.b SetRefhechLimiteFPSCanvasDrawingManager(CanvasNumber.i, FPS.i)
  Declare.b SetAutoRefrechCanvasDrawingManager(CanvasNumber.i, AutoRefrech.b)
  Declare.b SetImageCanvasDrawingManager(CanvasNumber.i, Image.i)
  
  Declare.i GetDrawingModeCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetDelayRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetRefhechPriorityCanvasDrawingManager(CanvasNumber.i)
  
  Declare.b GetAutoRefrechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.f GetMediumTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetTotaleTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetLoopRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetFPSRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetRefhechLimiteFPSCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetTimeWaitLoopLimiteFPSCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetMinimumFPSRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetMaximumFPSRefhechCanvasDrawingManager(CanvasNumber.i)
  Declare.i GetCanvasAttributeCanvasDrawingManager(CanvasNumber.i, CanvasAttribut.i)
  Declare.i GetImageCanvasDrawingManager(CanvasNumber.i)
  
  Declare.b ReleaseCanvasDrawingManager(CanvasNumber.i = #CanvasDrawingManager_All)
  
EndDeclareModule
Module CanvasDrawingManager
  
  ;{ Structure
  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.PrototypeCanvasDrawingCallBack ; 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'attend 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 MapCanvasDrawingManager.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 _IsCanvasDrawingManager(CanvasNumber) ; Pour usage dans le module
    Bool(IsGadget(CanvasNumber.i) And MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasInit = #True)
  EndMacro
  
  ;{ Procédures
  
  ;{ 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 IsCanvasDrawingManager(CanvasNumber.i)
    ProcedureReturn _IsCanvasDrawingManager(CanvasNumber)
  EndProcedure
  
  ; 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 CallBackEventCanvasDrawingManager()
    
    ; 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 = @MapCanvasDrawingManager(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 ThreadCanvasDrawingManager(CanvasNumber.i)
    
    ; Le pointeur '*Manager' pointe sur la structure 'StructureCanvasDrawingManager' à l'adresse du numéro du canevas.
    Protected *Manager.StructureCanvasDrawingManager = @MapCanvasDrawingManager(Str(CanvasNumber.i))
    
    ; Appelle une procédure de gestion des évènements du canevas.
    BindGadgetEvent(CanvasNumber.i, @CallBackEventCanvasDrawingManager(), #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 'SetCallBackCanvasDrawingManager'.
              ; Ceci utilise le prototype 'PrototypeCanvasDrawingCallBack', 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 'SetCallBackCanvasDrawingManager'.
              ; Ceci utilise le prototype 'PrototypeCanvasDrawingCallBack', 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 SetDelayRefhechCanvasDrawingManager().
        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
  
  ;{ 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 InitCanvasDrawingManager(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(MapCanvasDrawingManager(), 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(MapCanvasDrawingManager(), 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(@ThreadCanvasDrawingManager(), 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
  
  ;{ 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 SetDrawingModeCanvasDrawingManager(CanvasNumber.i, DrawingMode.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      If DrawingMode.i <> #CanvasDrawingMode2DDrawing And DrawingMode.i <> #CanvasDrawingModeVectorDrawing
        DrawingMode.i = #CanvasDrawingMode2DDrawing
      EndIf
      MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasDrawingMode = DrawingMode.i
      ProcedureReturn #True
    EndIf
    
    ProcedureReturn #False
    
  EndProcedure

  ;{ Définit la procédure de dessins du canevas.
  ;  CanvasNumber.i = Le numéro du canevas.
  ;  ProcedureDrawingCallBack.PrototypeCanvasDrawingCallBack = 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 SetCallBackCanvasDrawingManager(CanvasNumber.i, ProcedureDrawingCallBack.PrototypeCanvasDrawingCallBack, Value.i = 0)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasDrawingCallBack = ProcedureDrawingCallBack
      MapCanvasDrawingManager(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 SetDelayRefhechCanvasDrawingManager(CanvasNumber.i, Delay.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      
      If Delay.i < 0
        Delay.i = 0
      EndIf
      
      MapCanvasDrawingManager(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 SetRefhechPriorityCanvasDrawingManager(CanvasNumber.i, Priority.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      
      If Priority.i < 0
        Priority.i = 0
      ElseIf Priority.i > 32
        Priority.i = 32
      EndIf
      
      MapCanvasDrawingManager(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 SetAutoRefrechCanvasDrawingManager(CanvasNumber.i, AutoRefrech.b)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      
      MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasAutoRefrech = AutoRefrech.b
      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 SetRefhechLimiteFPSCanvasDrawingManager(CanvasNumber.i, FPS.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      
      If FPS.i <= 5
        FPS.i = 5
      EndIf
      
      MapCanvasDrawingManager(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 SetImageCanvasDrawingManager(CanvasNumber.i, Image.i)
    
    If IsCanvasDrawingManager(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 GetDrawingModeCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasDrawingMode
      
    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 GetAutoRefrechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasAutoRefrech
      
    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 GetDelayRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetRefhechPriorityCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(Str(CanvasNumber.i))\CanvasThreadPriority
    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 GetTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetMediumTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetTotaleTimeLoopRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetLoopRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetFPSRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetRefhechLimiteFPSCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetTimeWaitLoopLimiteFPSCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetMinimumFPSRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetMaximumFPSRefhechCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(CanvasNumber.i)
      ProcedureReturn MapCanvasDrawingManager(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 GetCanvasAttributeCanvasDrawingManager(CanvasNumber.i, CanvasAttribut.i)
    
    If IsCanvasDrawingManager(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(MapCanvasDrawingManager(), 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
  
  ;{ 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 GetImageCanvasDrawingManager(CanvasNumber.i)
    
    If IsCanvasDrawingManager(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(MapCanvasDrawingManager(), 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)
    
    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
  
  ;}
  
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()) 
Dernière modification par Shadow le dim. 04/déc./2022 2:56, modifié 2 fois.
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
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: CanvasDrawingManager

Message par Kwai chang caine »

Je ne suis pas un grand utilisateur du Canvas, alors j'y connais pas grand chose :oops:
J'ai testé ton code et un certain nombre de valeurs en bout des phrases se superposent apparemment chez moi :|
Du coup...ça fait des carrés noirs au bout d'un moment 8O
Je sais pas si c'est "ta maison" en fond ..... :mrgreen: mais ça tape sa race :lol:
En tout cas merci pour le partage 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Bonjour Kwai chang caine :)

Dites, vous êtes des codeur n'est ce pas ?
Bon, jvous demande pas de regarder le code du module ici, mais je suis sur que vous savez lire non ? :?:

J'ai tous documenté, yen a partout !..... ici à nautigames ! (Pour les connaisseur, robin des bois le dessins animé)
Et ya aussi des INSTRUCTIONS dans L'EXEMPLE !!!

Sérieux, quand ont teste un code, ont fais un minimum quoi non ?
Lire, c'est pas compliquer si ? :?

Allez jvé être sympa je vais les mettre ici puisque apparemment vous avez pas trouvé:
;{ INSTRUCTIONS:
; -------------

; - Il y a 2 Procédures de dessins qui font la même chose, une en mode 2DDrawing (Très rapide) et une en mode VectorDrawing (Très lent).
; - Pour cette exemple-ci, les FPS vont être limité à 10 par seconde, ceux-ci vont diminuer petit à petit jusqu'à atteindre 10 image par seconde.
; - Une fois arrivé à 10 FPS, ceux-ci vont être augmenter à 150, ceux-ci vont augmenter petit à petit jusqu'à atteindre 150 image par seconde maximum (Ou le maximum possible si 150 impossible).
; - NOTE: plus le nombre de FPS est important, plus il y aura d'images qui apparaîtront en une seconde, Avantage = Affichage Plus fluide, Désavantage = Consommes des ressources processeur.
;
; - A tous moment:
; - Cliquez sur le bouton gauche de la souris pour afficher l'image (Ou efface le canevas et afficher l'image si vous effacez le canevas dans la procédure de dessins).
; - Cliquez sur le bouton droit de la souris pour afficher de la neige (Recouvrira à force le canevas entier de blanc si vous n'effacez pas le canevas dans la procédure de dessins)
; - Cliquez sur le bouton centre de la souris pour Active ou désactive l'auto rafraichissement du canevas.
; - NOTE: (Si vous n'effacez pas le canevas dans la procédure de dessins, l'affichage ne sera pas rafraichie, les graphiques seront donc persistant).
;
; Voyez le programme évoluer en fonction de tous ces paramètres ainsi que le mode de dessins choisie, ya de quoi faire.
; Désactiver le Débuguer permet de gagné légèrement en vitesse.
; La gestion de Thread doit être activé dans les paramètres du compilateur (Activé Ici).
; -------------
;}
Sinon, oui très belle photo, c'est ça oui c'est chez moi exactement, c'est mon sateau ! :lol:
Nan mais c'est vers chez moi oui :)
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
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: CanvasDrawingManager

Message par Ar-S »

Dites, vous êtes des codeur n'est ce pas ?
Bon, jvous demande pas de regarder le code du module ici, mais je suis sur que vous savez lire non ? :?:
J'ai tous documenté, yen a partout !..... ici à nautigames ! (Pour les connaisseur, robin des bois le dessins animé)
Et ya aussi des INSTRUCTIONS dans L'EXEMPLE !!!
Sérieux, quand ont teste un code, ont fais un minimum quoi non ?
Lire, c'est pas compliquer si ?
C'est sûr qu'avec ce genre de réponse on va avoir envi de participer. :roll: KCC est clair.. Il parle pas de ton code mais de ce qui se passe lorsqu'il le teste. Si ce n'est pas ce à quoi tu t'attends, c'est que ton programme n'est pas intuitif. (je ne l'ai pas testé et ne le ferai pas pour l'instant).
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
Mindphazer
Messages : 635
Inscription : mer. 24/août/2005 10:42

Re: CanvasDrawingManager

Message par Mindphazer »

Moi je suis un aventurier, j'ai testé.
Ca fait plein de petites boules multicolores qui suivent le pointeur de la souris c'est joli :mrgreen:
Puis j'ai cliqué
1 fois
2 fois
Et paf IMA !

Bref, aucun intérêt --> Poubelle.
Bureau : Win10 64bits
Maison : Macbook Pro M1 14" SSD 512 Go / Ram 16 Go - iPad Pro 32 Go (pour madame) - iPhone 15 Pro Max 256 Go
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Mindphazer a écrit : lun. 14/févr./2022 10:40 Moi je suis un aventurier, j'ai testé.
Ca fait plein de petites boules multicolores qui suivent le pointeur de la souris c'est joli :mrgreen:
Puis j'ai cliqué
1 fois
2 fois
Et paf IMA !

Bref, aucun intérêt --> Poubelle.
Ah voici en vraie aventurier, tu as cliquer sur tous les bouton de la souris ?
Bref, aucun intérêt --> Poubelle.
Il faut différencier l'exemple du module !
L'exemple me semble pourtant pas si mal car il illustre bien les possibilités !
C'est sur que avec un exemple, on a du mal à ce représenter la chose je comprends !

Oui mon exemple est surement pas intuitif, j'ai un peu de mal c'est vraie mais j'ai fait l'effort de tous documenté !
Bon, je vous remercie pour vos retour, je vais améliorer tous ça et je reviens avec quelque chose de plus clair, intuitif :)
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
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: CanvasDrawingManager

Message par Kwai chang caine »

Ars a écrit :C'est sûr qu'avec ce genre de réponse on va avoir envi de participer. :roll: KCC est clair.
J'aime beaucoup mon copain SHADOW, enfin devrais-je plutôt dire "j'aimais beaucoup" :mrgreen:
Je l'ai toujours soutenu lors des nombreuses agressions "défensives" de certains membres qu'il a subit, de mon avis sans légitime raison ou sans proportion avec ce que l'on pourrait appeler "l'attaque" si tenté que ces démarches bien souvent maladroite, puisse donner l'impression d'une "attaque" :cry:
Mais là....j'vois pas 8O

Mon cher ARS, je te remercie d'avoir dit exactement ce que je pense, mais surtout de l'avoir dit beaucoup moins agressivement que je ne l'aurais fait :wink:
Dorénavant, comme cela ne plait pas à "MOSSIEU" le programmeur...je me garderais bien de me manifester pour quelque réaction que ce soit de ses codes.
Je gagnerais du temps....mais aussi une montée de tension, peu compatible avec mon état de santé :mrgreen:

ARS a écrit :Il parle pas de ton code mais de ce qui se passe lorsqu'il le teste. Si ce n'est pas ce à quoi tu t'attends, c'est que ton programme n'est pas intuitif.
Encore dans le mille "ARSSOUNET" :wink:
Je me suis juste risqué à donner l'effet visuel de son code...vu que c'est à peu prés juste ce que je suis capable de faire pour ce genre de code :oops:
Tout en prévenant qu'il fallait prendre mon avis comme celui d'un utilisateur LAMBDA, et ceci pour aider et informer le créateur de ce dernier d'un potentiel bug qu'il n'aurait pas vu ou eu, du fait des différentes machines ou bien tout autres raisons qui font qu'il est "normalement" agréable de faire essayer des codes et d'obtenir la confirmation ou l'infirmation de son bon fonctionnement, avant d'aller plus loin ou de le distribuer à plus de personnes 8)
C'est à dire, copier/coller, run et "regardage" 8O
Je la remet donc dans ma culotte....dans l'hypothétique espoir que d'autres membres "programmeurs" de ce forum comprennent et puisse expliquer à "MOSSIEU", pourquoi son code fait des gros pâtés en fin de ligne, outre les rondelles de couleurs bien jolies comme l'a si bien dit MindPhazer :wink:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Bonjour, Kwai chang caine

Ce message bien qu'il t'es été adresser n'étais pas que pour toi en faite !
Et je t'explique pourquoi j'ai été aussi cru, maladresse mais aussi incompréhension, et aussi énervement comme tu as pus le voir !
Au lieux d'être aussi catégorique, mais après c'est ton choix je le respecte ;)

Je me suis appliqué a faire ce programme, j'y est passer du temps, j'ai tous documenté, j'ai mis des jours à le faire,
puisque ont me reprochait parfois de pas documenté mes codes etc, là c'est bien fais !
Mais c'est pas encore assez bien !

Dans l'exemple, il y à bien écris en gros "INSTRUCTIONS", mais pas assez gros encore j'imagine !
Donc tous est documenté, je met des instructions mais c'est pas encore assez bien !

Quoi que je face c'est toujours nul, ya toujours un truc qui va pas, j'ai beau faire n'importe quoi c'est jamais bien !
Donc oui, ça m'as franchement bien énerver, j'ai le droits non ?

Je sais pas moi, quand je test un code, j'essaye au moins de lire un minimum, de comprendre
et pas juste tester bêtement comme ça et rapporter que le joujou il est cassé et que ça marche pas !

T'es énerver, navré, mais moi aussi, et je t'explique pourquoi voilà !
J'aime beaucoup mon copain SHADOW, enfin devrais-je plutôt dire "j'aimais beaucoup" :mrgreen:
Je réponds quoi à ça ?
Je l'ai toujours soutenu lors des nombreuses agressions "défensives" de certains membres qu'il a subit, de mon avis sans légitime raison ou sans proportion avec ce que l'on pourrait appeler "l'attaque" si tenté que ces démarches bien souvent maladroite, puisse donner l'impression d'une "attaque" :cry:
Exactement ;)
Dorénavant, comme cela ne plait pas à "MOSSIEU" le programmeur...je me garderais bien de me manifester pour quelque réaction que ce soit de ses codes.
Je gagnerais du temps....mais aussi une montée de tension, peu compatible avec mon état de santé :mrgreen:
Je sais que tu est une quiche comme tu le dis en code, mais c'est pas comme si j'avais pas écris des commentaire !
Quand tu achète quelque chose, généralement tu lis la notice, non ?, enfin quand tu sais pas quoi...
Façon personne ne lis les notice, moi compris, mais c'est parfois utile :mrgreen:

Donc malgré que j'ai encore cru bien faire avec mon code, c'est encore pas assez bien, même avec des explication et des commentaire !
Jme suis dis, ce sont pas des débile quand même, il savent au moins lire non ?

C'est parfaitement normale le fonctionnement du code, ya pas de bug, quand je fais un programme je le teste bien !
Donc oui jme suis un peu énerver, car jme suis dis que ce sont des codeurs et que s'il ne savent même pas lire une instruction, bha ça crain voila !

INSTRUCTIONS = pour les nul, ça veux dire, comment utiliser le machin, c'est si dur que ça !

Maintenant bien que j'ai cru bien faire, bha c'est encore pas assez, vous avez pas 2 ans si ?
Ont peut discuté aussi au lieux de s'énerver ? (Moi le premier ok j'avoue :oops: )

Est ce que c'est possible d'essayer de me comprendre aussi ?
Que chui pas très apprécier, Que je fais de mon mieux, que je partage, que je commente, que je donne des instructions et C'EST ENCORE PAS ASSEZ BIEN !

On a compris Shadow = poubelle, il est con, il écris comme un port, il s'exprime comme un gros teubé, il joue
à la victime tous le temps, il peu s'emporté, tous ce qu'il fais c'est nul et sa sert a rien et personne n'y comprends jamais rien !

Shadow est un extraterrestre voilà :)
Shadow personne ne l'aime, encore moins maintenant, car il s'exprime trop et comprends jamais rien !

Voilà désolé que ça parte encore en vrille par ma fautes, je devrais garder mes code a la gomme et fermer ma gueule !
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
Mindphazer
Messages : 635
Inscription : mer. 24/août/2005 10:42

Re: CanvasDrawingManager

Message par Mindphazer »

Désolé, mais des instructions sont faites pour
- Expliquer à quoi sert le programme
- Expliquer comment l'utiliser

Quand je lis ça
;{ INSTRUCTIONS:
; -------------

; - Il y a 2 Procédures de dessins qui font la même chose, une en mode 2DDrawing (Très rapide) et une en mode VectorDrawing (Très lent).
; - Pour cette exemple-ci, les FPS vont être limité à 10 par seconde, ceux-ci vont diminuer petit à petit jusqu'à atteindre 10 image par seconde.
; - Une fois arrivé à 10 FPS, ceux-ci vont être augmenter à 150, ceux-ci vont augmenter petit à petit jusqu'à atteindre 150 image par seconde maximum (Ou le maximum possible si 150 impossible).
; - NOTE: plus le nombre de FPS est important, plus il y aura d'images qui apparaîtront en une seconde, Avantage = Affichage Plus fluide, Désavantage = Consommes des ressources processeur.
ben je dois être une nouille, mais je ne comprends pas un mot de ce que tu veux dire
Bureau : Win10 64bits
Maison : Macbook Pro M1 14" SSD 512 Go / Ram 16 Go - iPad Pro 32 Go (pour madame) - iPhone 15 Pro Max 256 Go
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Mindphazer a écrit : lun. 14/févr./2022 15:07 Désolé, mais des instructions sont faites pour
- Expliquer à quoi sert le programme
- Expliquer comment l'utiliser

Quand je lis ça
;{ INSTRUCTIONS:
; -------------

; - Il y a 2 Procédures de dessins qui font la même chose, une en mode 2DDrawing (Très rapide) et une en mode VectorDrawing (Très lent).
; - Pour cette exemple-ci, les FPS vont être limité à 10 par seconde, ceux-ci vont diminuer petit à petit jusqu'à atteindre 10 image par seconde.
; - Une fois arrivé à 10 FPS, ceux-ci vont être augmenter à 150, ceux-ci vont augmenter petit à petit jusqu'à atteindre 150 image par seconde maximum (Ou le maximum possible si 150 impossible).
; - NOTE: plus le nombre de FPS est important, plus il y aura d'images qui apparaîtront en une seconde, Avantage = Affichage Plus fluide, Désavantage = Consommes des ressources processeur.
ben je dois être une nouille, mais je ne comprends pas un mot de ce que tu veux dire
Merci pour ton retour, c'est vraiment pas facile d'être clair :?
Je fais de mon mieux pourtant !

Les instruction sont pour l'exemple, pas pour le module !
Je suis en trains de revoir tous ça car c'est pas assez clair apparemment.
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
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: CanvasDrawingManager

Message par falsam »

Shadow tu devrais mettre ceci dans ton module pour être certain que les utilisateurs activent bien la gestion des thread dans les options de compilation.

Code : Tout sélectionner

;Option compilation  : [x] Thread
CompilerIf Not #PB_Compiler_Thread
  CompilerError "L'option activer la gestion des thread doit etre activer!"
CompilerEndIf
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

J'ai pris note et mis dans mon code, merci Falsam.
Une nouvelle version très amélioré devrait arriver d'ici peu de temps. :)
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
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: CanvasDrawingManager

Message par Micoute »

Bonjour Shadow,

j'ai essaye tes exemples et je les ai trouvés superbes, je ne savais même pas qu'on pouvait animer des images sur un canvas depuis le temps que je les utilise.

Continue sur ta lancée, car il y a longtemps que je n'avais pas vu un code aussi performant.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: CanvasDrawingManager

Message par Shadow »

Merci Micoute, je fais de mon mieux, et la suite arrive bientôt !
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
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: CanvasDrawingManager

Message par Micoute »

J'ai vraiment hâte de voir la suite.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Répondre