
'-------------------------------------------------------------------
'                                                          	       '
'     Hopefully some useful tips for people who are new to IWB     '
'               or just things you didn't know about or            '
'                          may find usefil.                        '
'                                                                  '
'                              By Andy.                            '
'                                                                  '
'                                                                  '
'  Please note:- Most of the following code was not written by me  '
'  but by other members of the IWB forum site - Thanks everyone!   ' 
'                                                                  ' 
'-------------------------------------------------------------------


'-------------------------------------------------------------------
'
' In this program we are going to check out how to:
'
' 1. Make it easy to assign control numbers.
' 2. Force upper case letters in an edit control.
' 3. Vertically center text of a static.
' 4. Limit the number of characters in an edit control.
' 5. Detect when text has changed in an edit control.
' 6. How to set the cursor to the end of any existing text.
' 7. Sub class a control so we can make it do what we want it to do. 
'
'-------------------------------------------------------------------

'
' This program:
'
' It's a program with four edit boxes and an OK button that simulates entering a
' license key.
'
' Each edit box can have only four uppercase letter.
'
' When an edit box has four characters, the program will jump to the next edit box.
'
' When all edit boxes have four letters in them, the OK button is clickable.

' You can use the backspace key to go back to the previous edit box.
'
' So let's begin.......


'This include file has many programming functions to help you - I almost always include this in all my code.
$include "windowssdk.inc"

'------------------------------------------------------------------------------------------------------------------
'
'         ---------------------------------
' FIRST - Setting up controls the easy way.
'         ---------------------------------
'
' This is very helpful - it makes it much quicker than this alternative:
'
' CONST EDIT_1 = 500
' CONST EDIT_2 = 501
' CONST EDIT_3 = 502 Etc...
'
' which is what I used to do for years (and still do sometimes)!
'
' Notice it automatically increments the control ID number, here (for no reason) we are starting at 500 for EDIT_1
' and BUT_OK will be assigned as 506.
'
'------------------------------------------------------------------------------------------------------------------

ENUM controls
	EDIT_1=500
	EDIT_2
	EDIT_3
	EDIT_4
	EDIT_5
	STATIC_1
	BUT_OK
endenum

window key

OPENWINDOW key,100,100,510,250,@CAPTION|@SYSMENU|@MINBOX|@MAXBOX|@TOPMOST,0," License key.",&handler_Key

'---------------------------------------------------------------------------------------------------
'
'        ------------------------------
' NEXT - Uppercase letters only please.
'        ------------------------------
'
' This is needed and added to the four edit control so they only display UPPERCASE letters - which is what I want here.
' It means I can type in lower case, but they appear as upper case in the edit box.
'
CONST ES_UPPERCASE = 0x8 '<----------
'
' So "ES_UPPERCASE" is added to each edit control preceeded by a "|" 
' which means you can add more options rather than just having one "Style"
'
'----------------------------------------------------------------------------------------------------------

CONTROL key,@EDIT,"",140,65,65,25,@CTEDITCENTER | ES_UPPERCASE, EDIT_1 '<--- Display letters as upper case.
CONTROL key,@EDIT,"",230,65,65,25,@CTEDITCENTER | ES_UPPERCASE, EDIT_2
CONTROL key,@EDIT,"",320,65,65,25,@CTEDITCENTER | ES_UPPERCASE, EDIT_3
CONTROL key,@EDIT,"",410,65,65,25,@CTEDITCENTER | ES_UPPERCASE, EDIT_4

'----------------------------------------------------------------------------------------------------------
'
'        -------------------------------------------
' NEXT - Vertically center text in a static control.
'        -------------------------------------------
'
' The 0X200 style (vertically center).
'
' Notice it's added into the static (STATIC_1).
'
' I want this static to appear nicely aligned with EDIT_1
' if I didn't use 0X200 I would have to move the control down by two from 65 (same as EDIT_1) to 67.
'
' Remember 0X200 - I use this all the time now for statics!
'
'---------------------------------------------------------------------------------------------------

CONTROL key,@STATIC,"Key please",20,65,110,25,@CTEDITRIGHT|0x200,STATIC_1 '<---- Note 0X200!
SETCONTROLCOLOR key,STATIC_1,rgb(0,0,0),RGB(255,255,255)

'---------------------------------------------------------------------------------------------------
'
'        -----------------------------------------------------
' NEXT - Limiting the number of characters in an edit control.
'        -----------------------------------------------------

' I want each edit box to be limited to just 4 characters, to do this you must use @EDSETLIMITTEXT
' followed by the number of characters.
'
' You have to do this after the edit contorl has been created.
'
'---------------------------------------------------------------------------------------------------

CONTROLCMD key,edit_1,@EDSETLIMITTEXT,4 '<---- Note @EDSETLIMITTEXT and 4 (for four characters only)

'---------------------------------------------------------------------------------------------------
'
'        -----------------------
' NEXT - Sub classing a control!
'        -----------------------
'
' What???????????????????????????? 
'
' Sub classing a control is in simplistic terms making a control do what 
' you want it to do - and not what it was simply deisgned to do (two different things!).
'
' Edit controls are designed to allow a user to type in it - okay,
' so if you can type it, it will go into an edit box.
'
' Now just supposing you only wanted capital letters A to Z, no spaces, dots, commas, numbers etc..
' then you have to sub class the edit control so that it only accepts letters A to Z
' and not everything that can be typed.
'
' This following sub routine (and the one it calls (EditHandler1 in this case) do exactly that,
' check out the sub routines:
'
' SubclassEdit and
' EditHandler1 now......
'
'----------------------------------------------------------------------------------------------------  

	SubclassEdit(key,edit_1) '<------ Sub routine to start sub classing EDIT_1.


' And we limit the text to four characters for the other edit boxes as well as sub classing them.
CONTROLCMD key,edit_2,@EDSETLIMITTEXT,4
	SubclassEdit(key,edit_2)

CONTROLCMD key,edit_3,@EDSETLIMITTEXT,4
	SubclassEdit(key,edit_3)

CONTROLCMD key,edit_4,@EDSETLIMITTEXT,4
	SubclassEdit(key,edit_4)

CONTROL key,@BUTTON,"OK",410,125,65,25,@CTEDITCENTER,BUT_ok



'Disable the BUT_OK button.
enablecontrol key,BUT_OK,0

'
' An easier way to set the font for multiple controls is to use a loop
' instead of doing it manually.....
'
' SETFONT key,"Arial",11,400,0,edit_1
' SETFONT key,"Arial",11,400,0,edit_2
' SETFONT key,"Arial",11,400,0,edit_3
' SETFONT key,"Arial",11,400,0,edit_4
' SETFONT key,"Arial",11,400,0,STATIC_1
' SETFONT key,"Arial",11,400,0,BUT_ok
'
' Here we go from the first control (EDIT_1) to the last control (BUT_OK)
'
' But you could use - FOR x = 500 TO 506 instead as they are the corresponding 
' control ID numbers.
'
' And you can use the same method to set control colours etc...
'

int x
for x = EDIT_1 to BUT_OK
    SETFONT key,"Arial",11,400,0,x
next x

' Just something between each edit box.
MOVE key,214,68
PRINT key,"--"

MOVE key,304,68
PRINT key,"--"

MOVE key,394,68
PRINT key,"--"


SETFOCUS key,EDIT_1
WAITUNTIL key = 0 
end

'----------------------------------
'
' The window's handler
'
'----------------------------------

SUB handler_Key(),int

SELECT @MESSAGE

    CASE @IDCONTROL

        SELECT @CONTROLID

				case EDIT_1

						'---------------------------------------------------------------------------------------------------
						'
						'        ---------
						' NEXT - ENCHANGE!
						'        ---------
                  '
                  ' This one I missed for years!
                  '
                  ' It allows you (unlike IF @NOTIFYCODE=0) to do checks on the control itself as it's being "changed"
                  ' In this case - typed in.
                  '
						'---------------------------------------------------------------------------------------------------

						if @NOTIFYCODE=@ENCHANGE

                     'My simple sub routine to check that all edit boxes have four
                     'characters each - if so, enable the ok button (BUT_OK).

							if EnableButtonCheck() = 0

								if len(getcontroltext(key,edit_1)) = 4 '<--- EDIT_1 has four characters, so move to EDIT_2.
									setfocus key,edit_2
								endif

                     endif 

						endif

				case EDIT_2

						if @NOTIFYCODE=@ENCHANGE

							'---------------------------------------------------------------------------------------------------
							'
							'        -----------
							' NEXT - AppendEdit.
							'        -----------
							'
							' This is very useful to know.
                     '  
							' When a user clicks on an edit control that already has text in it, 
							' it sets the cursor to the end of the text, and not at the beginning (which is the default).
                     ' 
                     ' Here we are doing this for EDIT_1.
							'   
							'---------------------------------------------------------------------------------------------------

                     AppendEdit(key,edit_1,"",0) '<--- Set the cursor to the end of any existing text in EDIT_1.

							if EnableButtonCheck() = 0

								if len(getcontroltext(key,edit_2)) = 4 '<--- EDIT_2 has four characters, so move to EDIT_3.
 									setfocus key,edit_3
								endif

                     endif

						endif


				case EDIT_3

						if @NOTIFYCODE=@ENCHANGE

                     AppendEdit(key,edit_2,"",0)

							if EnableButtonCheck() = 0

								if len(getcontroltext(key,edit_3)) = 4
									setfocus key,edit_4
								endif

                     endif

						endif

				case EDIT_4

						if @NOTIFYCODE=@ENCHANGE

                     AppendEdit(key,edit_3,"",0)

							EnableButtonCheck()

						endif

            CASE BUT_ok

						if @NOTIFYCODE=0

							'---------------------------------------------------------------------------------------------------
							'
							'        ---------------------
							' NEXT - Remove the sub class.
							'        ---------------------
                     '
                     ' When we sub class any control, it's good practice to remove that sub class from the control 
                     ' before exiting the program - OR - if you then want to use the control normally later.
                     ' 
							'---------------------------------------------------------------------------------------------------  

							UnSubclassEdit(key,EDIT_1)
							UnSubclassEdit(key,EDIT_2)
							UnSubclassEdit(key,EDIT_3)
							UnSubclassEdit(key,EDIT_4)

							closewindow key
							end
						endif

        endselect

		CASE @IDCREATE
			  centerwindow key

    case @IDCLOSEWINDOW

         ' Same as clicking the OK button, just end the program.

			UnSubclassEdit(key,EDIT_1)
			UnSubclassEdit(key,EDIT_2)
			UnSubclassEdit(key,EDIT_3)
			UnSubclassEdit(key,EDIT_4)

         closewindow key 
         end

endselect
return 0
endsub

'
' Just my routine to enable / disable the OK button.
'

sub EnableButtonCheck(),int 

if len(getcontroltext(key,edit_1)) = 4 and len(getcontroltext(key,edit_2)) = 4 and len(getcontroltext(key,edit_3)) = 4 and len(getcontroltext(key,edit_4)) = 4
   enablecontrol key,BUT_OK,1
   setfocus key,BUT_OK
   return 1
else
   enablecontrol key,BUT_OK,0
   return 0
endif

return 0
endsub

'---------------------------------------------------------------------------------------------------
'
' -------------------------------------------------------------
' This routine sets the cursor to the end of any existing text.
' -------------------------------------------------------------
'
'---------------------------------------------------------------------------------------------------

CONST WM_GETTEXTLENGTH = 0xE
Sub AppendEdit(window win,int id,string text,int addNL)
	int _textlen:_textlen =SendMessage(win, WM_GETTEXTLENGTH,0,0,id)
	ControlCmd win, id, @EDSETSELECTION, _textlen, _textlen
	if(addNL)
		ControlCmd win, id, @EDREPLACESEL, text + "\n"
	else
		ControlCmd win, id, @EDREPLACESEL, text
	endif
RETURN
ENDSUB

'---------------------------------------------------------------------------------------------------
'
' -------------
' Sub Classing.
' -------------
'
' Lets sub class (change the edit control to do what we want them to do)!
'
' Here I have four slight variations of the same code, one for each edit control
' as each one does a slightly different thing when pressing the tab / backspace keys.
'
' EditHandler1, EditHandler2, EditHandler3 & EditHandler4.
'
'---------------------------------------------------------------------------------------------------

SUB SubclassEdit(parent:WINDOW,id:INT)
   hEdit = GETCONTROLHANDLE(parent,id)

   if id = EDIT_1
		lpFn = SetWindowLongA(hEdit,-4,&EditHandler1) '<--- Do this for EDIT_1: now look at the EditHandler1 sub routine. 
		SetPropA(hEdit,"edit_handler1",lpFn)
   endif

   if id = EDIT_2
		lpFn = SetWindowLongA(hEdit,-4,&EditHandler2)
		SetPropA(hEdit,"edit_handler2",lpFn)
   endif

   if id = EDIT_3
		lpFn = SetWindowLongA(hEdit,-4,&EditHandler3)
		SetPropA(hEdit,"edit_handler3",lpFn)
   endif

   if id = EDIT_4
		lpFn = SetWindowLongA(hEdit,-4,&EditHandler4)
		SetPropA(hEdit,"edit_handler4",lpFn)
   endif

RETURN
ENDSUB

'---------------------------------------------------------------------------------------------------
'
' ------------
' EditHandler1
' ------------
'
' Check characters typed in the edit box.
'
' Here we are checking what characters are being typed in EDIT_1, and only allowing what we want
' that is - letters A to Z, a backspace (so you can delete text), 
' and Tab (so we can tab to the next edit control (EDIT_2 in this case).
'
'---------------------------------------------------------------------------------------------------

SUB EditHandler1(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT
    SELECT uMsg

			 CASE @IDCHAR

            IF (wParam = 0x8) 'Backspace key was pressed - do something.
					if len(getcontroltext(key,edit_1)) = 0
						setfocus key,edit_1
					endif
            endif

            IF (wParam = 0x9) 'Tab key was pressed - do something (go to the next edit control)
                              'but only if EDIT_1 has four characters.
               if len(getcontroltext(key,edit_1)) = 4
					   setfocus key,edit_2
               endif
            endif

            '-------------------------------------------------------------------------------------------------------
            '  
            ' Here we are checking each character as it is typed.
            '
            ' On the ASCII table, all the lowercase letters start at 61 (hex) and finish at 7A (hex).
            '
            ' Wait - I'm confused!!!
            '
            ' Didn't you say YOU ONLY WANTED CAPITAL letters - not lower case ones??????
            '
            ' Remember the "ES_UPPERCASE" style we added to EDIT_1?
            '
            ' What's actually happening is i'm typing without caps lock on - i.e. typing in lower case letters.
            ' 
            ' So the actual letters being typed are in lower case - but thanks to "ES_UPPERCASE", they appear 
            ' as capitals - watch for this - they are not the same!
            '
            ' This following line checks each character typed in EDIT_1 to see if IT IS NOT a lower / upper case A to Z, a backspace
            ' and a Tab.
            '
            ' If it is not a character / key stroke we want - it returns "fail" i.e. 1
            ' - otherwise allow it. 
            '
            ' Note:-
            '
            ' Each character's "ASCII number" is stored in the variable "wParam"  
            ' so we check the value of wParam to see if it's a character we want.
            '
            ' wParam must be: 
            ' 
            ' 0X41 to 0X5A 	(Upper case letters A - Z (added in just in case the user does type in upper case)).
            ' 0X61 to 0X7A 	(Lower case letters a - z).
            ' 0X8 				(Backspace).
            ' 0X9 				(Tab).
            '
            '
            ' Phew!!!!!! 
            '
            '
            '------------------------------------------------------------------------------------------------------

            'Check the character typed....
				IF ((wParam < 0x41) OR (wParam > 0x5A)) and ((wParam < 0x61) OR (wParam > 0x7A)) AND (wParam <> 0x08) AND (wParam <> 0x09) THEN RETURN 1 '<-- Not a character we want.
ENDSELECT
RETURN CallWindowProcA(GetPropA(hWnd,"edit_handler1"),hWnd,uMsg,wParam,lParam)
ENDSUB

'-----------------------------------------------------
'  
' Here we do the same checks for the other edit boxes.
'
'-----------------------------------------------------

SUB EditHandler2(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT
    SELECT uMsg

			 CASE @IDCHAR

            IF (wParam = 0x8) 'Backspace
					if len(getcontroltext(key,edit_2)) = 0
						setfocus key,edit_1
					endif
            endif

            IF (wParam = 0x9) 'Tab
               if len(getcontroltext(key,edit_2)) = 4
					   setfocus key,edit_3
               endif 
            endif

				IF ((wParam < 0x41) OR (wParam > 0x5A)) and ((wParam < 0x61) OR (wParam > 0x7A)) AND (wParam <> 0x08) AND (wParam <> 0x09) THEN RETURN 1
ENDSELECT
RETURN CallWindowProcA(GetPropA(hWnd,"edit_handler2"),hWnd,uMsg,wParam,lParam)
ENDSUB

SUB EditHandler3(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT
    SELECT uMsg

			 CASE @IDCHAR

            IF (wParam = 0x8) 'Backspace
					if len(getcontroltext(key,edit_3)) = 0
						setfocus key,edit_2
					endif
            endif

            IF (wParam = 0x9) 'Tab
               if len(getcontroltext(key,edit_3)) = 4
					   setfocus key,edit_4
               endif
            endif

				IF ((wParam < 0x41) OR (wParam > 0x5A)) and ((wParam < 0x61) OR (wParam > 0x7A)) AND (wParam <> 0x08) AND (wParam <> 0x09) THEN RETURN 1
ENDSELECT
RETURN CallWindowProcA(GetPropA(hWnd,"edit_handler3"),hWnd,uMsg,wParam,lParam)
ENDSUB

SUB EditHandler4(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT
    SELECT uMsg

			 CASE @IDCHAR

            IF (wParam = 0x8) 'Backspace
					if len(getcontroltext(key,edit_4)) = 0
						setfocus key,edit_3
					endif
            endif

				IF ((wParam < 0x41) OR (wParam > 0x5A)) and ((wParam < 0x61) OR (wParam > 0x7A)) AND (wParam <> 0x08) THEN RETURN 1
ENDSELECT
RETURN CallWindowProcA(GetPropA(hWnd,"edit_handler4"),hWnd,uMsg,wParam,lParam)
ENDSUB

'---------------------------------------------------------------------------------------------------
'
' When we sub class any control, it's good practice to remove that sub class from the control 
' before exiting the program - OR - in case we want to use it normally later.
' 
' This routine removes the subclass from the controls.
'
'---------------------------------------------------------------------------------------------------  

SUB UnSubclassEdit(parent:WINDOW,id:INT)
   hEdit = GETCONTROLHANDLE(parent,id)

   if id = EDIT_1
		SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler1"))
      RemovePropA(hEdit,"edit_handler1")
   endif

   if id = EDIT_2
		SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler2"))
      RemovePropA(hEdit,"edit_handler2")
   endif

   if id = EDIT_3
		SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler3"))
      RemovePropA(hEdit,"edit_handler3")
   endif

   if id = EDIT_4
		SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler4"))
      RemovePropA(hEdit,"edit_handler4")
   endif

RETURN
ENDSUB

'---------------------------------------------------------------------------------------------------
'
' End of tutorial.
'
'---------------------------------------------------------------------------------------------------

