Don't ask me again

BlitzMax Forums/MaxGUI Module/Don't ask me again

JoshK(Posted 2006) [#1]
Don't ask me again.

I am attempting to make a custom messagebox, with a check box at the bottom, like this:


I can retrieve the system font to set the messagebox size, and maybe retrieve the icon with an API function. My biggest problem right now is I need to eliminate the default icon that appears on the left end of the title bar of a Blitz window. Anyone know how?

Extern "win32"
	Function MessageBeep:Byte(nType)
EndExtern

Notify "Real MessageBox"
MessageBoxPlus("My MessageBox")



Function MessageBoxPlus:Int(message$)
	w=168
	h=126
	
	messagebeep $40
		
	bw=75
	bh=23
	bi=11
		
	win:TGadget=CreateWindow(AppTitle$,(Desktop().ClientWidth()-w)/2,(Desktop().ClientHeight()-h)/2,w,h,Null,WINDOW_TITLEBAR)

	button:TGadget=CreateButton("OK",(win.clientwidth()-bw)/2,win.clientheight()-bh-2-bi,bw,bh,win)
	ActivateGadget button
	setfocus QueryGadget(button,QUERY_HWND)

	'w=TextWidth(message)
	
	w=80
	h=16
	
	CreateLabel message,(win.clientwidth()-w)/2,(win.clientheight()-h-bh-bi)/2,w,h,win,LABEL_CENTER
	
	Repeat
		Select WaitEvent()
			Case EVENT_GADGETACTION
				Select EventSource()
					Case button
						Exit
				EndSelect
			Case EVENT_WINDOWCLOSE
				Select EventSource()
					Case win
						Exit
				EndSelect
		EndSelect
	Forever
	FreeGadget win
	Return result
EndFunction



Brendane(Posted 2006) [#2]
You can get rid of the system menu (the close button is part of this so if you want a close button you'll need a way to add your own custom button)

Note the calls to SetWindowLong() - to modify the window style - and SetWindowPos() to force the changes to update the window

SuperStrict

Extern "win32"
	Function MessageBeep:Byte(nType:Int)
	Function SetWindowLong:Int(hwnd:Int,index:Int,value:Int)="SetWindowLongA@12"
	Function GetWindowLong:Int(hWnd:Int, index:Int)="GetWindowLongA@8"
EndExtern

Notify "Real MessageBox"
MessageBoxPlus("My MessageBox")



Function MessageBoxPlus:Int(message$)
	Local w:Int=168
	Local h:Int=126
	
	messagebeep $40
		
	Local bw:Int=75
	Local bh:Int=23
	Local bi:Int=11
		
	Local win:TGadget=CreateWindow(AppTitle$,(Desktop().ClientWidth()-w)/2,(Desktop().ClientHeight()-h)/2,w,h,Null,WINDOW_TITLEBAR)

	' Modify the window's style
	Local hWnd:Int = QueryGadget(win, QUERY_HWND )
	Local style:Int = GetWindowLong(hWnd, GWL_STYLE ) & (~WS_SYSMENU)
	SetWindowLong( hWnd, GWL_STYLE, style  )
	' Must call SetWindowPos to force the frame to update
	SetWindowPos( hWnd, 0,0,0,0,0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER )


	Local button:TGadget=CreateButton("OK",(win.clientwidth()-bw)/2,win.clientheight()-bh-2-bi,bw,bh,win)
	ActivateGadget button
	setfocus QueryGadget(button,QUERY_HWND)

	'w=TextWidth(message)
	
	w=80
	h=16
	
	CreateLabel message,(win.clientwidth()-w)/2,(win.clientheight()-h-bh-bi)/2,w,h,win,LABEL_CENTER

	
	Repeat
		Select WaitEvent()
			Case EVENT_GADGETACTION
				Select EventSource()
					Case button
						Exit
				EndSelect
			Case EVENT_WINDOWCLOSE
				Select EventSource()
					Case win
						Exit
				EndSelect
		EndSelect
		
	Forever
	FreeGadget win
	Return 0
EndFunction



JoshK(Posted 2006) [#3]
That's better, but the lack of a close button really bugs me. It's got to be possible, because I see applications that have the top-left icon removed, all the time. The Firefox options window is one example.

Apparently, someone over at PureBasic was able to do this by adding WS_EX_DLGMODALFRAME to the GWL_EXSTYLE:
OpenWindow(0, 0, 0, 240, 100, "Modal frame", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_Invisible)
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_DLGMODALFRAME)
HideWindow(0, 0)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow


However, it doesn't work in BlitzMax:
Extern "win32"
	Function SetWindowLong:Int(hwnd:Int,index:Int,value:Int)="SetWindowLongA@12"
	Function GetWindowLong:Int(hWnd:Int, index:Int)="GetWindowLongA@8"
EndExtern

Local w=400
Local h=300
Local win:TGadget=CreateWindow("Window",(Desktop().ClientWidth()-w)/2,(Desktop().ClientHeight()-h)/2,w,h,Null,WINDOW_HIDDEN+WINDOW_TITLEBAR)
Local hWnd:Int = QueryGadget(win,QUERY_HWND)

SetWindowLong hWnd,GWL_EXSTYLE,GetWindowLong(hwnd,GWL_EXSTYLE)+WS_EX_DLGMODALFRAME
SetWindowPos( hWnd, 0,0,0,0,0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER )
ShowGadget win

While WaitEvent()<>EVENT_WINDOWCLOSE
Wend


Now that I stopped and noticed how almost every program uses child windows without that top-left-corner icon, this is bugging me a lot. Open Paint Shop Pro or FireFox, and everything uses the same icon-less child window.


Brendane(Posted 2006) [#4]
Hi,

It's not the window class style / ex_style which controls that. I have just set up the two windows (PureBasic and MaxGUI) with exactly the same flags (verified by using MS Spy to observe the window styles). The PB window displays only the close button (as you want it) but the Max window displays the system menu also.

I believe the only way is to keep the sys menu and take control of the caption drawing yourself (also you will need to remove the system menu or prevent it from being popped up). Perhaps PB has some built in code for this. The alternative is to disable the sysmenu as shown above but add your own custom close button to the titlebar.

Never mind, I'm sure that Windows Vista will be nicer to work with (not).


JoshK(Posted 2006) [#5]
Given how common this window style is, I think it highly unlikely that it requires an owner-drawn title bar.










JoshK(Posted 2006) [#6]
This code creates a dialog box, a window with the desired style. However, it's not a Blitz gadget, it's just a windows hwnd. If I had a way to create an empty gadget, or to switch the hwnd of a gadget, it might work.
Extern "win32"
	Function CreateDialogIndirectParamA:Int(hInstance:Int,lpTemplate:Byte Ptr,hWndParent,lpDialogFunc:Byte Ptr,lParamInit)
	Function DialogBoxIndirectParamA:Int(hinstance,hDialogTemplate:Byte Ptr,hWndParent,lpDialogFunc:Byte Ptr,dwInitParam)
	Function EndDialog:Int(hDlg,nResult)
EndExtern

Type DLG_TEMPLATE
    Field style:Int
    Field dwExtendedStyle:Int
    Field cdit:Short
    Field x:Short
    Field y:Short
    Field cx:Short
    Field cy:Short
    Field menu:Short
    Field class:Short
    Field title:Int
EndType

Const DS_MODALFRAME=128

dlg:DLG_TEMPLATE=New DLG_TEMPLATE
dlg.style=WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_CENTER | WS_VISIBLE
dlg.x=0
dlg.y=0
dlg.cx=200
dlg.cy=100

Function DlgProc:Int(hWnd, uMsg, wParam, lParam)
    Select uMsg
    Case WM_INITDIALOG
    Case WM_COMMAND
        EndDialog(hWnd,wParam&$FFFF)
    EndSelect
    Return 0
EndFunction

win:TGadget=CreateWindow("",200,200,400,300)
hwnd=QueryGadget(win,QUERY_HWND)
CreateDialogIndirectParamA(0,dlg,hwnd,DlgProc,0)

While WaitEvent()<>EVENT_WINDOWCLOSE
Wend



xlsior(Posted 2007) [#7]
.