Transparent shadow image as window's background?

Everything else that doesn't fall into one of the other PB categories.
ankachen
User
User
Posts: 12
Joined: Tue Mar 27, 2007 2:52 am

Transparent shadow image as window's background?

Post by ankachen »

When I set transparent shadow image as window's background, I couldn't
alignment any gadgets inside the window. Any solution will be appreciated.

CreateGadgetList(WindowID(0))
ButtonGadget(1,20,20,100,50,"Button")

The button doesn't visible in the following code.

Here is the image : ftp://leon.serveftp.net/ftp/BG.png

Code: Select all

UsePNGImageDecoder() 
Global WorkDir.s = ""
WorkDir.s = Space(1000)
GetCurrentDirectory_(1000,@WorkDir)
WorkDir = WorkDir + "\"

OpenWindow(0, 0, 0, 512, 384, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu) 
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED) 

CreateGadgetList(WindowID(0))
LoadImage(0, WorkDir +"BG.png") 
CreateGadgetList(WindowID(0))
ButtonGadget(1,20,20,100,50,"Button")
hdc = StartDrawing(ImageOutput(0)) 
GetObject_(ImageID(0), SizeOf(BITMAP), @BitmapInfo.BITMAP) 
ContextOffset.POINT 
BlendMode.BLENDFUNCTION 
BlendMode\SourceConstantAlpha = 255 
BlendMode\AlphaFormat = 1 

UpdateLayeredWindow_(WindowID(0), 0, 0, @BitmapInfo+4, hdc, @ContextOffset, 0, @BlendMode, 2) 

StopDrawing() 

Repeat 
  Select WaitWindowEvent() 
    Case #PB_Event_CloseWindow 
      Break 
  EndSelect 
ForEver
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

I see a problem with your code, but I'd rather not comment until I can test with your image. I can't download it, could you make sure it's available?
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

I still can't get your PNG so I'll whip one up and show you where you're at with this:

To do the demo you need this: http://www.lloydsplace.com/BG.png

You have two main issues that must be overcome:

Firstly, the PNG image decoder that ships with PureBasic is currently incompatible with the UpdateLayeredWindow API. So you must decode the image using another tool. I've supplied you with an arrow from my quiver, so that's out of the way.

Secondly, sad to report, Microsoft has made windows using the UpdateLayeredWindow API unable to host child windows. This is due to the fact that it uses a different, per-pixel update routine to draw the window and it doesn't process #WM_PAINT messages like a normal window does. So, while the child controls exist, they are never drawn.

The UpdateLayeredWindow approach has one major advantage over other forms of skinning or achieving transparency in that you can create dropshadows for the window edges and they will render correctly. In fact, it's the only technology on Windows I know of that will achieve this. So, we must find a way to make it work.

Here we go, this is our plan:

Make a Layered window with dropshadowed edges for use as a window border only.

Make another toplevel window to host the gadgets and keep it centered on the first window at all times.

As hackitistically perverted as this idea is, it actually is one of the options suggested by Microsoft engineers as a solution to this known limitation.

On to the hack!

Code: Select all

;========================================= 
; Danger, netmaestro software ahead 
;========================================= 

ProcedureDLL CatchPNG(ImageNumber, Address, Length) 

  CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0 
    Structure GdiplusStartupInput 
      GdiPlusVersion.l 
      *DebugEventCallback.Debug_Event 
      SuppressBackgroundThread.l 
      SuppressExternalCodecs.l 
    EndStructure 
  CompilerEndIf  
  
  Structure StreamObject 
    block.l 
    *bits 
    stream.ISTREAM 
  EndStructure 

  Protected lib 
  lib = OpenLibrary(#PB_Any, "gdiplus.dll") 
  If Not lib 
    ProcedureReturn -1 
  EndIf 
  
  input.GdiplusStartupInput 
  input\GdiPlusVersion = 1 
  
  CallFunction(lib, "GdiplusStartup", @*token, @input, #Null) 
  If *token 
    stream.streamobject 
    Stream\block = GlobalAlloc_(#GHND, Length) 
    Stream\bits = GlobalLock_(Stream\block) 
    CopyMemory(address, stream\bits, Length) 
    If CreateStreamOnHGlobal_(stream\bits, 0, @Stream\stream) = #S_OK 
      CallFunction(lib, "GdipCreateBitmapFromStream", Stream\stream , @*image) 
      Stream\stream\Release() 
      GlobalUnlock_(Stream\bits) 
      GlobalFree_(Stream\block) 
    Else 
      CallFunction(lib, "GdiplusShutdown", *token) 
      ProcedureReturn 0 
    EndIf 
    
    If *image 
      CallFunction(lib, "GdipGetImageWidth", *image, @Width.l) 
      CallFunction(lib, "GdipGetImageHeight", *image, @Height.l) 
      If imagenumber = #PB_Any
        return_imagenumber = CreateImage(#PB_Any, Width, Height, 32)
      Else
        CreateImage(return_imagenumber, Width, Height, 32, #PB_Image_Transparent)
      EndIf
      hDC = StartDrawing(ImageOutput(return_imagenumber)) 
        CallFunction(lib, "GdipCreateFromHDC", hdc, @*gfx) 
        CallFunction(lib, "GdipDrawImageRectI", *gfx, *image, 0, 0, Width, Height) 
      StopDrawing()  
      CallFunction(lib, "GdipDeleteGraphics", *gfx)  
      CallFunction(lib, "GdipDisposeImage", *image) 
      CallFunction(lib, "GdiplusShutdown", *token) 
      CloseLibrary(0) 
      
      ProcedureReturn return_imagenumber 
    Else 
      ProcedureReturn -1
    EndIf 
  Else 
    ProcedureReturn -1
  EndIf 
EndProcedure 

Procedure WinProc(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_MOVE, #WM_ACTIVATE, #WM_ACTIVATEAPP, #WM_GETICON 
      ResizeWindow(0,WindowX(1)+96, WindowY(1)+30, #PB_Ignore, #PB_Ignore) 
    Case #WM_LBUTTONDOWN 
      If EventlParam()>>16<21
        SendMessage_(hwnd, #WM_NCLBUTTONDOWN, #HTCAPTION, 0) 
      EndIf
  EndSelect 
  ProcedureReturn result 
EndProcedure 

CatchPNG(0, ?bkimg, ?endbk-?bkimg) 

OpenWindow(1, 0, 0, 512, 384, "", #PB_Window_ScreenCentered | #PB_Window_BorderLess) 
OpenWindow(0, 0, 0, 300, 200, "", #PB_Window_BorderLess, WindowID(1) ) 

SetWindowLong_(WindowID(1), #GWL_EXSTYLE, GetWindowLong_(WindowID(1), #GWL_EXSTYLE) | #WS_EX_LAYERED) 
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED) 

SetLayeredWindowAttributes_(WindowID(0), 0, 255, #LWA_ALPHA) ; Not necessary but just to show it's ok to do it 
SetWindowColor(0, RGB(131,193,178)) ; Same color as PNG 

hdc = StartDrawing(ImageOutput(0)) 
  sz.SIZE 
  sz\cx = ImageWidth(0) 
  sz\cy = ImageHeight(0) 
  ContextOffset.POINT 
  BlendMode.BLENDFUNCTION 
  BlendMode\SourceConstantAlpha = 255 
  BlendMode\AlphaFormat = 1 
  UpdateLayeredWindow_(WindowID(1), 0, 0, @sz, hDC, @ContextOffset, 0, @BlendMode, 2) 
StopDrawing() 

SetWindowCallback(@WinProc(),1) 

ButtonGadget(1,20,20,100,30,"Press to exit...") 
  
Repeat 
  Select WaitWindowEvent() 
    Case #PB_Event_Gadget 
      Break 
    Case #PB_Event_CloseWindow 
      Break 
  EndSelect 
ForEver 

DataSection 
  bkimg:
  IncludeBinary "BG.png" 
  endbk: 
EndDataSection
Last edited by netmaestro on Wed Aug 19, 2015 10:02 pm, edited 1 time in total.
BERESHEIT
ankachen
User
User
Posts: 12
Joined: Tue Mar 27, 2007 2:52 am

Post by ankachen »

Wow! Your solution was terrific!! Thank you for helping.
I was clarified on this issue.

Thanks again!!
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

That is Hacktastic!!!! 8) Netmaestro Rulez!!!!

I am seriously impressed.
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

netmaestro wrote:

Code: Select all

;========================================= 
; Danger, netmaestro software ahead 
;========================================= 
:lol:
Dare2 cut down to size
Post Reply