Page 1 of 1

Transparent background for canvas ?

Posted: Sat Nov 30, 2013 2:59 pm
by Joubarbe
Hi,

I'd like to have three-states buttons (on, hot and off), so I use canvas to make them, with custom images. My problem is that canvas has a white background by default, and I'm unable to make it 100% transparent. That way, I could have alpha gradients on my buttons and disregard the background color of my window, which can use alpha channel too.

What I'm currently doing is something like this :

Code: Select all

; ...
CanvasGadget(0, 0, 0, 50, 50)
SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(#CanvasOff)) ; I use a Redraw() procedure to make it persistent when the user moves the window out of the screen
ImageGadget(1, 0, 0, 640, 480, ImageID(#BackgroundImage))

BindGadgetEvent(0, @CanvasMouseEnter(), #PB_EventType_MouseEnter)
BindGadgetEvent(0, @CanvasMouseLeave(), #PB_EventType_MouseLeave)
BindGadgetEvent(0, @CanvasMouseClick(), #PB_EventType_LeftClick) 
; and I use SetGadgetAttribute() in each procedure to change the image of the canvas
... and in that case, if the image of my button uses the alpha channel, then the white background color of the canvas will appear and mess things up.

Re: Transparent background for canvas ?

Posted: Sat Nov 30, 2013 3:26 pm
by davido
You normally change the background colour of a CanvasGadget by drawing a Box with the required colour.

It should be possible to use the alpha channel to make it transparent.

Re: Transparent background for canvas ?

Posted: Sat Nov 30, 2013 3:28 pm
by Joubarbe
Well I've tried that of course, but drawing a box does not replace the background color. It just adds a box over the background.

Re: Transparent background for canvas ?

Posted: Sat Nov 30, 2013 5:12 pm
by IdeasVacuum
Not sure why you need the canvas to be transparent, if it's 'back' is an image anyway? Unfortunately, a CanvasGadget() can't be made transparent (perhaps it can on Windows via the API).
That way, I could have alpha gradients on my buttons and disregard the background color of my window, which can use alpha channel too.
If that were to happen, you would see right through to the desktop - surely you don't want to do that?

Re: Transparent background for canvas ?

Posted: Sat Nov 30, 2013 5:18 pm
by Joubarbe
IdeasVacuum wrote:Not sure why you need the canvas to be transparent, if it's 'back' is an image anyway? Unfortunately, a CanvasGadget() can't be made transparent (perhaps it can on Windows via the API).
I use photoshop elements such as glows and shadows and if I want to use this button on a window whose background is a gradient (even a subtle one), I need to have a transparent support, otherwise a part of the button won't have seamless borders.
If that were to happen, you would see right through to the desktop - surely you don't want to do that?
Sorry, I meant "... which can use gradients too".

Re: Transparent background for canvas ?

Posted: Sat Nov 30, 2013 11:03 pm
by netmaestro
Here's a technique that lets you draw anything alphablended to a transparent canvasgadget. A lot of the code is boilerplate, so it really isn't too much work to customize it for a specific purpose. It only works on windows, so if you aren't on windows I just did a lot of work for nothing :lol:

Code: Select all

Prototype AlphaBlend(hdcDest,DestX,DestY,DestW,DestH,hdcSrc,SrcX,SrcY,SrcW,SrcH,BLENDFUNCTION)

msimg32 = OpenLibrary(#PB_Any, "msimg32.dll")
Global AlphaBlend_.AlphaBlend = GetFunction(msimg32, "AlphaBlend")

Global hBkgndBrush
Global MyCanvasOutput = CreateImage(#PB_Any, 120,40,32,#PB_Image_Transparent)

Procedure PreMultiply(image)
  StartDrawing(ImageOutput(image))
    DrawingMode(#PB_2DDrawing_AllChannels)
    For j=0 To ImageHeight(image)-1
      For i=0 To ImageWidth(image)-1
        color = Point(i,j)
        Plot(i,j, RGBA(Red(color)   & $FF * Alpha(color) & $FF / $FF,
                       Green(color) & $FF * Alpha(color) & $FF / $FF,
                       Blue(color)  & $FF * Alpha(color) & $FF / $FF,
                       Alpha(color)))
      Next
    Next
  StopDrawing()
EndProcedure

Procedure canvasproc(hwnd, msg, wparam, lparam)
  
  oldproc = GetProp_(hwnd, "oldproc")
  
  Select msg
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")
      
    Case #WM_ERASEBKGND
      
      hdc = wparam
      GrabImage(0,1,GadgetX(0),GadgetY(0),GadgetWidth(0),GadgetHeight(0))
      hBrush = CreatePatternBrush_(ImageID(1))
      hPen = GetStockObject_(#NULL_PEN)
      SelectObject_(hdc, hBrush )
      SelectObject_(hdc, hPen)
      Rectangle_(hdc,0,0,121,41)
      DeleteObject_(hBrush)
      ProcedureReturn #True
      
    Case #WM_PAINT
      BeginPaint_(hwnd, ps.PAINTSTRUCT)
      hdcDest = ps\hdc
      hdcSrc = StartDrawing(ImageOutput(MyCanvasOutput))
      result=AlphaBlend_(hdcDest,0,0,ImageWidth(MyCanvasOutput),ImageHeight(MyCanvasOutput),hdcSrc,0,0,ImageWidth(MyCanvasOutput),ImageHeight(MyCanvasOutput),$1FF0000)
      StopDrawing()
      EndPaint_(hwnd, hdcDest)
      ProcedureReturn #False
      
  EndSelect
  
  ProcedureReturn  CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
EndProcedure

OpenWindow(0,0,0,320,240,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CreateImage(0, 320,240)
StartDrawing(ImageOutput(0))
  DrawingMode(#PB_2DDrawing_Gradient)
  GradientColor(0.0, #Blue)
  GradientColor(1.0, #White)
  LinearGradient(0,0,0,240)
  Box(0,0,320,240)
StopDrawing()
hBkgndBrush = CreatePatternBrush_(ImageID(0))
SetClassLong_(WindowID(0), #GCL_HBRBACKGROUND, hBkgndBrush)
InvalidateRect_(WindowID(0),0,1)

CanvasGadget(0,100,100,120,40)
SetProp_(GadgetID(0), "oldproc", SetWindowLongPtr_(GadgetID(0), #GWL_WNDPROC, @canvasproc()))

StartDrawing(ImageOutput(MyCanvasOutput))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  Box(3,3,106,30,RGBA(255,0,0,255))
  DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
  DrawText(8,9,"Veni, Vidi, Vici.", RGBA(255,0,0,255))
StopDrawing()
PreMultiply(MyCanvasOutput)

Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow

If IsLibrary(msimg32)
  CloseLibrary(msimg32)
EndIf

Re: Transparent background for canvas ?

Posted: Sun Dec 01, 2013 10:12 am
by Joubarbe
Thanks netmaestro ; indeed that's a lot of lines :)

Re: Transparent background for canvas ?

Posted: Sun Dec 01, 2013 4:22 pm
by netmaestro
You're welcome! Unfortunately there is no native way to accomplish transparency in a canvasgadget. Mind you, the task can be done in quite some fewer lines. The WM_ERASEBACKGROUND message could be done away with and its brush moved to WM_PAINT, where it could be combined with the foreground stuff via DrawAlphaImage and then output with BitBlt. Because it would cover the entire background, no erase would be needed and the premultiply and imports for AlphaBlend_() could be removed. The result would be a lot slimmer.