Changing+the+step+size+of+an+up-down+control

//by Richard Russell, July 2014//

When you create an **up-down control** you can easily choose the minimum and maximum values, and the direction in which it changes (i.e. whether clicking on the up arrow increases or decreases the value). However you cannot choose the step size: each click always changes the value by either +1 or -1 (or zero if the limit has been reached).

To modify the behaviour of the up-down control requires a small piece of assembler code. The simplest option is to change the step size to a value other than one; the code example below demonstrates setting it to five: code format="bb4w" REM!WC UDN_DELTAPOS = -722 WM_NOTIFY = 78 ES_NUMBER = 8192 UDM_SETRANGE = 1125

INSTALL @lib$+"WINLIB2" dlg% = FN_newdialog("test1",100,100,100,100,8,200)

PROC_editbox(dlg%,"50",101,10,10,50,10,ES_NUMBER) PROC_dlgctrl(dlg%,"",102,0,0,0,0,&50000096,"msctls_updown32")

PROC_showdialog(dlg%) PROCsetdelta(!dlg%, 102, 5) SYS "SendDlgItemMessage", !dlg%, 102, UDM_SETRANGE, 0, (0 << 16) + 100 SYS "SetDlgItemText", !dlg%, 101, "40"

ON ERROR PROC_closedialog(dlg%):PRINT REPORT$:END ON CLOSE PROC_closedialog(dlg%):QUIT

REPEAT WAIT 1 UNTIL FALSE PROC_closedialog(dlg%) END

DEF PROCsetdelta(hdlg%, udid%, delta%) LOCAL D%,M%,O%,P% PRIVATE C%,L% : IF C%=0 DIM C% 100, L% -1 P% = C%     SYS "GetWindowLong", hdlg%, -4 TO O%      [OPT 10 .D% pop eax : push O% : push eax : jmp "CallWindowProc" .M% cmp dword [esp+8],WM_NOTIFY : jnz D%     mov edx,[esp+16] : cmp dword [edx+4],udid% : jnz D%      cmp dword [edx+8],UDN_DELTAPOS : jnz D%      mov eax,[edx+16] : imul eax,delta% : mov [edx+16],eax xor eax,eax : ret 16 ]     SYS "SetWindowLong", hdlg%, -4, M%      ENDPROC code The procedure **PROCsetdelta** takes three parameters: the handle of the dialogue box, the ID of the up-down control and the desired step size.

However this may not always be what you want. Suppose that the contents of the associated edit box are initially 1 rather than 0 (for example because the user has typed in that value). Now, when you click the up button, the value will change to 6, then 11, then 16 and so on. You might prefer that instead of **adding** (or subtracting) 5, the up-down control changes the value to the next **multiple** of 5, so that the first click will change it from 1 to 5 (rather than 6). That can be achieved using this slightly more complicated code: code format="bb4w" REM!WC UDN_DELTAPOS = -722 WM_NOTIFY = 78 ES_NUMBER = 8192 UDM_SETRANGE = 1125

INSTALL @lib$+"WINLIB2" dlg% = FN_newdialog("test1",100,100,100,100,8,200)

PROC_editbox(dlg%,"50",101,10,10,50,10,ES_NUMBER) PROC_dlgctrl(dlg%,"",102,0,0,0,0,&50000096,"msctls_updown32")

PROC_showdialog(dlg%) PROCsetdelta(!dlg%, 102, 5) SYS "SendDlgItemMessage", !dlg%, 102, UDM_SETRANGE, 0, (0 << 16) + 100 SYS "SetDlgItemText", !dlg%, 101, "41"

ON ERROR PROC_closedialog(dlg%):PRINT REPORT$:END ON CLOSE PROC_closedialog(dlg%):QUIT

REPEAT WAIT 1 UNTIL FALSE PROC_closedialog(dlg%) END

DEF PROCsetdelta(hdlg%, udid%, delta%) LOCAL D%,M%,O%,P% PRIVATE C%,L% : IF C%=0 DIM C% 100, L% -1 P% = C%     SYS "GetWindowLong", hdlg%, -4 TO O%      [OPT 10 .D% pop eax : push O% : push eax : jmp "CallWindowProc" .M% cmp dword [esp+8],WM_NOTIFY : jnz D%     mov edx,[esp+16] : cmp dword [edx+4],udid% : jnz D%      cmp dword [edx+8],UDN_DELTAPOS : jnz D%      mov eax,[edx+12] : mov ecx,delta% : xor edx,edx : idiv ecx : mov ecx,edx mov edx,[esp+16] : imul ecx,[edx+16] bt ecx,31 : adc eax,[edx+16] : imul eax,delta% sub eax,[edx+12] : mov [edx+16],eax xor eax,eax : ret 16 ]     SYS "SetWindowLong", hdlg%, -4, M%      ENDPROC code