How to make non rectangular windows

BlitzMax Forums/MaxGUI Module/How to make non rectangular windows

-Phoenix-(Posted 2011) [#1]
First, I would like to say : I am aware that this topic has been discussed before, however the solution offered doesn't seem to work anymore with the new versions of Max Gui

A non rectangular window would be a window that not only doesn't have a border, but also has a shape defined by an image with alpha channel or mask color.

The former solution was based on the functions :

Extern "Win32"
Function SetWindowRgn(hWnd, hRgn, bRedraw)
Function CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect)
Function CombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, fnCombineMode)
End Extern

However when I use the sample :

Import MaxGui.Drivers
Strict

Const HTCAPTION = 2
Const RGN_XOR = 3

Extern "Win32"
	Function SetWindowRgn(hWnd, hRgn, bRedraw)
	Function CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect)
	Function CombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, fnCombineMode)
End Extern

Local skinPmap:TPixmap = LockImage(LoadImage("Background.png"))
If skinPmap = Null Then RuntimeError "Oi...Where's me picture?"

Local window:TGadget = CreateWindow("", 100, 100, skinPmap.width, skinPmap.height, Null,0)
SkinWindow(window, skinPmap)
'SetGadgetShape(Window,100,100,100,500)
ShowGadget(window)
Local canvas:TGadget = CreateCanvas(0, 0, ClientWidth(window), ClientHeight(window), window)
Local hWnd = QueryGadget(window, QUERY_HWND) 
			SetGraphics CanvasGraphics(canvas)
			SetBlend ALPHABLEND
			DrawPixmap skinPmap, 0, 0
	
			Flip		

Repeat
	Select WaitEvent()
		Case EVENT_MOUSEDOWN 
			ReleaseCapture()
			SendMessageA(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, Null)
	
		Case EVENT_KEYDOWN
			If CurrentEvent.data = 27 Then End
		
		Case EVENT_GADGETPAINT
			SetGraphics CanvasGraphics(canvas)
			DrawPixmap skinPmap, 0, 0
	
			Flip		
	End Select
Forever

End

Function SkinWindow(window:TGadget, skin:TPixmap)
	Local rectRgn = CreateRectRgn(0, 0, GadgetWidth(window), GadgetHeight(window))
	Local hWnd = QueryGadget(window, QUERY_HWND_CLIENT)
	
	For Local pixY=0 Until skin.height
		Local startFlag = 0
		Local startX = 0
		Local maskLine, pixX
		
		For pixX=0 Until skin.width
			Local argb = ReadPixel(skin, pixX, pixY) 		
	
			If argb & $ff000000 = 0
				If startFlag = 0
					startFlag = 1
					startX = pixX
				EndIf
			Else
				If startFlag
					startFlag = 0
					maskLine = CreateRectRgn(startX, pixY, pixX, pixY + 1)
					CombineRgn(rectrgn, rectrgn, maskLine, RGN_XOR)
					DeleteObject(maskLine)
				EndIf
			EndIf 			
		Next
		If startFlag
			maskLine = CreateRectRgn(startX, pixY, pixX, pixY + 1)
			CombineRgn(rectrgn, rectrgn, maskLine, RGN_XOR)
			DeleteObject(maskLine)
		EndIf
	Next
	
	SetWindowRgn(hWnd, rectrgn, True)
End Function


I end up with a rectangular gray area around the window

any ideas?


Midimaster(Posted 2011) [#2]
there are three errors in your code

1. QUERY_HWND_CLIENT is the wrong handle
2. your start pixel finder is not working
3. the XOR is the wrong combination

see this to continue:
Function SkinWindow(window:TGadget, skin:TPixmap)
	Local rectRgn = CreateRectRgn(0, 0, GadgetWidth(window), GadgetHeight(window)/2)
	Local hWnd = QueryGadget(window, QUERY_HWND)
		Local maskLine, pixX
	maskLine = CreateRectRgn(0, 0, GadgetWidth(window)/2, GadgetHeight(window))

	CombineRgn(rectrgn, rectrgn, maskLine, 2)
	SetWindowRgn(hWnd, rectrgn, True)
end function	



-Phoenix-(Posted 2011) [#3]
thanks, I got it working after replacing QUERY_HWND_CLIENT by QUERY_HWND, the rest is working though, start pixel and XOR is correct (try it?)


Midimaster(Posted 2011) [#4]
here is my solution:

Function SkinWindowII(Window:TGadget , Skin:TPixmap)
	Const NOTHING=-1
	Local RectRgn = CreateRectRgn(0, 0, 0,0)
	Local hWnd = QueryGadget(Window , QUERY_HWND)
	Local X% , Y% , StartX% , argb:Long
	
	For Y=0 Until Skin.Height
		For X=0 Until Skin.Width
		
			argb = ReadPixel(skin, X, Y) 		
			If (argb <> NOTHING)
				If StartX = -1
					StartX = X
				EndIf
			Else
				If StartX > -1 
					Local MaskLine
					MaskLine = CreateRectRgn( StartX , Y , X , Y+1 )
					CombineRgn ( RectRgn , RectRgn, MaskLine , 2 )
					DeleteObject MaskLine
					StartX = -1
				EndIf
			EndIf
		Next
		If StartX > -1 
			Local MaskLine
			MaskLine = CreateRectRgn( StartX , Y, X , Y+1 )
			CombineRgn ( RectRgn , RectRgn , MaskLine, 2 )
			DeleteObject MaskLine
			StartX = -1
		EndIf
	Next
	SetWindowRgn ( hWnd , RectRgn , True)
End Function	


My first rectangle is empty, with futher rectangles I do an "AND"-combination.

I don't know why, but I have to take argb=-1 to detect an empty pixel, the $FF000000 seems not to work correct with my 8bit-PNG-Picture on my computer.

Last edited 2011

Last edited 2011


-Phoenix-(Posted 2011) [#5]
Found the problem on my start position finder, also you have a slight mistake :

For Y=0 Until Skin.Height
For X=0 To Skin.Width

should be :

For Y=0 Until Skin.Height
For X=0 Until Skin.Width

thanks for the help


Midimaster(Posted 2011) [#6]
thanks too!

this is very strange: when I published the code in the morning it worked perfectly with a "For X=0 TO...".

Now my girlfriend came home. I wanted to demonstrate it, but now I got an error and changed it to "For X= 0 UNTIL..."