Basic Univers
; Permet de créer une fenêtre skinnée avec une image. Un effet de transparence pourra être appliqué à certaines zones de l'images (couleur définie)

; Structure BITMAP
;   bmType.l
;   bmWidth.l
;   bmHeight.l
;   bmWidthBytes.l
;   bmPlanes.w
;   bmBitsPixel.w
;   bmBits.l
; EndStructure

#Gdi = 0
#User = 1

OpenLibrary(#Gdi, "gdi32.dll")
OpenLibrary(#User, "user32.dll")


Procedure RegionColor(hBmp, color)
  If hBmp ; si le handle n'est pas nul
   
   ;{ déclaration de variables
   
      hDC_bmp.l
      bmpstruct.bitmap ;
      transparent.l
      LineRegion = 0
      FullRegion = 0
      In_Line = 0
      In_First_Region = 1
      StartLine_X = 0
   
    ;}
     
      If CallFunction(#Gdi, "GetObjectA", hBmp, SizeOf(BITMAP), @bmpstruct) = 0 ; on récupère des informations sur l'image et on vérifie le handle
      ProcedureReturn 0 ;
      EndIf
     
hDC_bmp = CallFunction(#Gdi, "CreateCompatibleDC", 0) ; on crée un device contexte

      If hdc_bmp = 0 ; on vérifie qu'il aie été créé
      ProcedureReturn 0 ;
      EndIf
     
hBmp_old = CallFunction(#Gdi, "SelectObject", hDC_bmp, hBmp) ; on met l'image dans le dc

      transparent = color ; on récupère la couleur transparente
     
For y = 0 To bmpstruct\bmHeight - 1 ; on "scanne"
       
         For x = 0 To bmpstruct\bmWidth ; l'image
         
           
            If CallFunction(#Gdi, "GetPixel", hDC_bmp, x, y) = transparent Or x = bmpstruct\bmWidth ; si la couleur du point est celle de transparence ou que l'on est à la droite de l'image, cela veux dire que l'on doit stopper la selection
               
               If In_Line ; si avant il y avait un pixel coloré
                                 
                  In_Line    = 0 ; on remet à zéro
                  LineRegion = CallFunction(#Gdi, "CreateRectRgn", StartLine_X, y, x, y + 1) ; on sélectionne une région rectangulaire d'une hauteur de 1 et d'une largeur correspondant au nombre de pixels non-transparent précédants le pixel transparent
                 
                  If In_First_Region ; si c'est la première région que l'on sélectionne
                 
                     In_First_Region = 0 ; on remet à zéro
                     FullRegion = LineRegion ; la région globale pour le moment sera cette région
                 
                  Else
                 
                     CallFunction(#Gdi, "CombineRgn", FullRegion, FullRegion, LineRegion, 2) ; sinon la région globale est l'union de la région globale actuelle plus celle que l'on viens de séléctionner
                 
                     CallFunction(#Gdi, "DeleteObject", LineRegion) ; on n'a plus besoin de cette région maintenant
                 
                  EndIf
               
                EndIf
           
            ElseIf In_Line = 0 ; sinon si avant le pixel est tranparent
           
               In_Line     = 1 ; on précise que le pixel est maitenant coloré
               StartLine_X = x ; on garde la position de ce pixel afin de plus tard selectionner une région coloré
           
            EndIf
         Next
      Next
     
      CallFunction(#Gdi, "DeleteDC", hDC_bmp) ; et on supprime le dc
     
      ProcedureReturn FullRegion ; on renvoie le région finale
   
   EndIf
   
   ProcedureReturn 0

EndProcedure

Procedure SkinColor(WindowID, ImageID, color = 0)
CallFunction(#User, "SetWindowRgn", WindowID, RegionColor(ImageId, color), #True)
EndProcedure

If OpenWindow(0, 0, 0, 300, 300, "Skin", #PB_Window_BorderLess | #PB_Window_ScreenCentered) = 0 Or CreateGadgetList(WindowID(0)) = 0
  End
EndIf
; La fenêtre doit obligatoirement être avec le style #PB_Window_BorderLess

SetWindowColor(0, RGB(255, 0, 0))


; On crée une image qui va servir de skin (elle doit avoir la taille de la fenêtre)
CreateImage(0, 300, 300)
StartDrawing(ImageOutput(0))
  ; La couleur mauve $FF00FF ou RGB(255, 0, 255) représente la partie transparente de la fenêtre
  Box(250, 0, 50, 30, $FF00FF)
  Circle(200, 200, 50, $FF00FF)
  Circle(250, 230, 50, $FF00FF)
  Ellipse(50, 120, 40, 20, $FF00FF)
  LineXY(50, 50, 250, 100, $FF00FF)
StopDrawing()

Temps = ElapsedMilliseconds()

; ExtCreateRegion : a voir

SkinColor(WindowID(0), ImageID(0), $FF00FF)

Temps = ElapsedMilliseconds() - Temps

; On place un bouton pour quitter
ButtonGadget(0, 0, 0, 100, 25, "Quitter")
; On affichage le temps nécesssaire pour créer le masque
TextGadget(#PB_Any, 0, 25, 100, 15, Str(Temps) + " ms")

Repeat
  Event = WaitWindowEvent()
 
  If Event = 513
   OpenLibrary(0, "user32.dll")
    CallFunction(0, "SendMessage", WindowID(0), 161, 2, 0)
  EndIf
 
  If Event = #PB_Event_Gadget
    Select EventGadget() ; boutons, zone de texte, ...
      Case 0 ; On quitte le programme
        Event = #PB_Event_CloseWindow
    EndSelect
  EndIf
 
Until Event = #PB_Event_CloseWindow

End