
'================================================================
'
' This code is based on Fasecero's Unicode combo box example.
'
' What I've triedd to do here is to document how it works.
'
' This program will produce a text file called 1.txt in the same
' folder, so after you run the program you can see more clearly
' how a combo box works.
'
' Thnaks again Fasecero!
'
' Andy.
'
'================================================================

$INCLUDE "windowssdk.inc"
$INCLUDE "Commctrl.inc"

CONST COMBO_1 = 10
INT subclassID = 12345
INT hwnd_combo = 0
WINDOW w1
file f1
wstring DisplayText  = L""

OPENWINDOW w1,0,0,600,400,@MINBOX|@MAXBOX|@SIZE,NULL,"Unicode combo box example.",&w1_handler
CONTROL w1,@BUTTON,"Button",10,290,120,25,0x50000000,2

' Main loop
WAITUNTIL w1 = 0
END
 
' Window procedure
SUB w1_handler
	SELECT @MESSAGE
		CASE @IDCREATE
			CENTERWINDOW w1
         openfile(f1,getstartpath() + "1.txt","W")

			OnInit() '<--- Step 1, please look at this sub routine first.

         write f1,""
         write f1,"Window is open."
         write f1,""

         write f1,""
         write f1,"COMBO_1's control handle = " + str$(getcontrolhandle(w1,COMBO_1)) 
			write f1,""

		CASE @IDCLOSEWINDOW
			CLOSEWINDOW w1
         closefile f1
			OnFinish()

		CASE @IDCONTROL
			SELECT @CONTROLID
					 case 2
                     if @notifycode=0
                        'Do Something
                        openconsole
                        closeconsole
                     endif 

			endselect
	ENDSELECT
ENDSUB

SUB OnInit()

   '===================================================================================
   '
	' Step 1 - Subclass the window...
   ' 
   ' Here we need to sub class the window, i.e. so we can track COMBO_1
   ' the control we want to make responsive / get information from.
   '
   ' We need a sub routine to do this, we can name it anything, here
   ' it's called 'subclassProc'.
   '
   ' We need to pass this to the 'SetWindowSubclass' command as a pointer 
   ' so we refer to it here with a '&' symbol i.e. '&subclassProc'. 
   '
   '===================================================================================

	SetWindowSubclass(w1.hwnd, &subclassProc, subclassID, 0)

	' Initialise common controls. 
	_InitCommonControls()
			
	' Create the Unicode combo box control here... 
	INT dwStyles = CBS_DROPDOWNLIST | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE 
	hwnd_combo = CreateCombo(w1.hwnd, 10, 10, 200, 100, COMBO_1, dwStyles)
			
	' Add some items to it.
	ComboAddString(hwnd_combo, L"First")
	ComboAddString(hwnd_combo, L"Second")
	ComboAddString(hwnd_combo, L"Third")
	ComboAddString(hwnd_combo, L"Forth")
	
	' Select the second item - for no reason at all.
	ComboSelectItem(hwnd_combo, 1) ' zero based index
	
	' The first time you have to manually update the position yourself
	OnIndexChange(hwnd_combo)


   '=============================================================
   ' Now for step 2, please look at the sub routine subclassProc.
   '=============================================================

ENDSUB

SUB subclassProc(hWnd:INT,uMsg:INT,wParam:INT,lParam:INT,uIdSubclass:UINT_PTR,dwRefData:DWORD_PTR),INT

'=====================================================================================================
'
' Step 2 - Our sub class routine, subclassProc.
'
' The parameters here are strict, if you read MSDN regarding SetWindowSubclass, it actually tells
' you this structure.
'
' We need not look too deep into this, expect for certain parameters we will need, here they are:
'
' uMsg
' wParam
' lParam.
'
'
' For this sub routine, we are only interested in 'listening' for the windows command WM_COMMAND.
' And uMsg contains the command values passed to here.
'
' As we only want WM_COMMAND we can use SELECT uMsg, then CASE WM_COMMAND.
'
' Here I have surrounded the whole section with an IF uMsg = 273 to compact the output text file that 
' you can read when you have run the program.
'
'=====================================================================================================

	if uMsg = 273 ' = WM_COMMAND (0x111)

		SELECT uMsg '<--- Select a message...

			CASE WM_COMMAND '<--- This is the message we want...

				write f1,"WM_COMMAND = " + str$(WM_COMMAND)

            '=======================================================================  
            '   
            ' WM_COMMAND sends some details / values, one of which is called wParam.
            '    
            '
            ' Now wParam has two values, a low word value and a high word value 
            ' but given to us as one single value containing both.
            '
            ' To get thses two values, we can use two built in windows macros called
            ' LOWORD & HIDORD.
            '
            ' So instead of SELECT wParam we use....
            '
            '    SELECT LOWORD(wParam)
            '    SELECT HIWORD(wParam)
            '
            '======================================================================= 
 
				SELECT LOWORD(wParam) '<---- The specific control ID - here we only need COMBO_1

					CASE COMBO_1 '<--- So are only interested in COMBO_1
							write f1,"Control Selected = " + str$(LOWORD(wParam)) + " COMBO_1's control ID."
							write f1,"HIWORD(wParam) = " + str$(HIWORD(wParam)) 

							SELECT HIWORD(wParam) '<--- Combo_1 notification messages sent.

                       '=========================================================== 
                       '
                       ' The notification message we are really interested in here
                       ' is CBN_SELCHANGE, but I've included others so you can see  
                       ' how the combo box functions.
                       '
                       '=========================================================== 

								CASE CBN_SETFOCUS
										write f1,"COMBO_1 now has the focus. <----------------"
										write f1,""

								case CBN_DROPDOWN
										write f1,"Drop down box clicked (Opened). <----------------"
										write f1,""

								case CBN_SELENDOK
										write f1,"An item was selected. <----------------"
										write f1,""

								CASE CBN_CLOSEUP
										write f1,"Drop down box is closed. <----------------"
										write f1,""

								CASE CBN_SELENDCANCEL
										write f1,"User closed the drop down list or no more selections at this time. <----------------"
										write f1,""

								CASE CBN_KILLFOCUS
										write f1,"COMBO_1 has lost focus now. <----------------"
										write f1,""

                        '============================================================================================================================================
	 
								CASE CBN_SELCHANGE ' The user has selected another item...
										write f1,"Item selected " + str$(CBN_SELCHANGE) + " = CBN_SELCHANGE (has a value of 1) - Message to Parent window. <----------------"
										write f1,"lParam = " + str$(lParam) + " COMBO_1's control handle. <----------------"
										write f1,""

                              ' Just a sub routine to get the selected combo box item number...
										OnIndexChange(lParam)

                              ' Display the text from the selected item...
										DisplayText = L""
										GetWindowTextW(GetDlgItem(w1.hwnd,COMBO_1),DisplayText,512)
										move w1,10,100
										print w1,"                                     "
										move w1,10,100
										print w1,DisplayText

                        '============================================================================================================================================

							ENDSELECT
				ENDSELECT
		ENDSELECT
	endif

	RETURN DefSubclassProc(hWnd, uMsg, wParam, lParam)
ENDSUB

SUB OnIndexChange(int handle) ' aux func
	 INT index = SendMessageW(handle, CB_GETCURSEL, 0, 0)
	 SETCAPTION w1, "Selected position: " + STR$(index + 1)
ENDSUB

SUB OnFinish()
   'Remove the sub class from the window to tidy up...
	RemoveWindowSubclass(w1.hwnd, &subclassProc, subclassID)
ENDSUB

' ------------------------------------------------------------------------------------------------------------
' UNICODE FUNCTIONS
' ------------------------------------------------------------------------------------------------------------

SUB _InitCommonControls()
	' Ensures that the common control DLL (Comctl32.dll) is loaded, and registers specific common control classes from the DLL.
	' An application must call this function before creating a common control.
	INITCOMMONCONTROLSEX icc
	icc.dwSize=LEN(icc)
	icc.dwICC= ICC_BAR_CLASSES | ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS
	InitCommonControlsEx (&icc)
ENDSUB

SUB CreateCombo(INT parent, int x, int y, int dimx, int dimy, int ctrl, int style), INT
	RETURN CreateWindowExW(0, WC_COMBOBOXW, L"", _
        style, _
        x, y, dimx, dimy, _
        parent, ctrl, GetModuleHandle(0), 0)
ENDSUB

SUB ComboAddString(INT handle, pointer text)
	SendMessageW(handle, CB_ADDSTRING, 0, text)
ENDSUB

SUB ComboSelectItem(INT handle, int index)
	SendMessageW(handle, CB_SETCURSEL, index, 0)
ENDSUB
