NsDialogs FAQ: Difference between revisions
No edit summary |
(Added radio button examples) |
||
(44 intermediate revisions by 11 users not shown) | |||
Line 85: | Line 85: | ||
Section "" | Section "" | ||
SectionEnd | |||
</highlight-nsis> | |||
== How to create a label with center-aligned text == | |||
Center-aligned text - where the text is always centered within the control, no matter its size, is often useful for presentation purposes. Making a label's text center-aligned is simple, using [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-addstyle ${NSD_AddStyle}] add the ${SS_CENTER} style. | |||
<highlight-nsis> | |||
!include "nsDialogs.nsh" | |||
OutFile "$%temp%\temp.exe" | |||
var dialog | |||
var hwnd | |||
var null | |||
Page custom Test | |||
Function Test | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateLabel} 0 0 100% 20% "This line will be centered.$\nAnd so will this line." | |||
Pop $hwnd | |||
${NSD_AddStyle} $hwnd ${SS_CENTER} | |||
nsDialogs::Show | |||
FunctionEnd | |||
Section | |||
SectionEnd | SectionEnd | ||
</highlight-nsis> | </highlight-nsis> | ||
== How to create a multi-line edit (text) control == | == How to create a multi-line edit (text) control == | ||
Although multi-line is a Style of a control, for Edit (Text) controls it is one of few | Although multi-line is a Style of a control, for Edit (Text) controls it is one of few styles that cannot be set once the control has already been created - so you can't use ${NSD_AddStyle}. | ||
Instead, you will have to create the control manually: | Instead, you will have to create the control manually: | ||
Line 154: | Line 182: | ||
== How to create a Text Password control == | == How to create a Text Password control == | ||
See the [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html nsDialogs] documentation - a Password control is one of the controls supported by default; ${NSD_CreatePassword} | See the [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html nsDialogs] documentation - a Password control is one of the controls supported by default; ${NSD_CreatePassword} | ||
== How to set the character used by a Text Password control == | |||
By default a Text Password control will use asterisks (*****) with '[http://nsis.sourceforge.net/Docs/Chapter4.html?title=XPStyle#4.8.1.46 XPStyle] off', or fat dots with 'XPStyle on' as the password characters to mask the text. You can change this character using [http://nsis.sourceforge.net/Docs/Chapter4.html#4.9.14.10 SendMessage] with the [http://social.msdn.microsoft.com/Search/en-US/?query=win32+EM_SETPASSWORDCHAR EM_SETPASSWORDCHAR] flag. | |||
The password character is identified by its ASCII or UNICODE index; keep in mind that the font you use for your installer may not support the character you wish to use. | |||
'''NOTE''' If you set the password character to 0 (zero), the text will ''not'' be masked! You can use this to toggle between the text being visible and masked. | |||
See also the [[NsDialogs_FAQ#How_to_hide.2Fshow_passwords_in_a_Text_Password_control|How to hide/show passwords in a Text Password control]] entry. | |||
<highlight-nsis> | |||
!include "nsDialogs.nsh" | |||
!include "winmessages.nsh" | |||
!include "logiclib.nsh" | |||
OutFile "test.exe" | |||
Page Custom pre | |||
var dialog | |||
var hwnd | |||
Function pre | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreatePassword} 0 0 50% 8% "This is a password field" | |||
Pop $hwnd | |||
SendMessage $hwnd ${EM_SETPASSWORDCHAR} 149 0 # 149 = medium dot | |||
nsDialogs::Show | |||
FunctionEnd | |||
Section "" | |||
SectionEnd | |||
</highlight-nsis> | |||
== How to hide/show passwords in a Text Password control == | |||
By using [http://nsis.sourceforge.net/Docs/Chapter4.html#4.9.14.10 SendMessage] with the [http://social.msdn.microsoft.com/Search/en-US/?query=win32+EM_SETPASSWORDCHAR EM_SETPASSWORDCHAR] flag, specifying the character as 0 (zero), you can make a password visible, and invisible again by specifying a non-zero character. | |||
See also the [[NsDialogs_FAQ#How_to_set_the_character_used_by_a_Text_Password_control|How to set the character used by a Text Password control]] entry. | |||
'''NOTE''' The Password control has to be forcibly redrawn after changing the mask character. This is done by hiding and then showing the control using [http://nsis.sourceforge.net/Docs/Chapter4.html#4.9.14.17 ShowWindow]. | |||
<highlight-nsis> | |||
!include "nsDialogs.nsh" | |||
!include "winmessages.nsh" | |||
!include "logiclib.nsh" | |||
OutFile "test.exe" | |||
Page Custom pre | |||
var dialog | |||
var hwnd | |||
var passwordControl | |||
Function pre | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateCheckbox} 0 0 25% 8% "Show password" | |||
Pop $hwnd | |||
${NSD_OnClick} $hwnd ShowPassword | |||
${NSD_CreatePassword} 0 10% 50% 8% "This is a password field" | |||
Pop $passwordControl | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function ShowPassword | |||
Pop $hwnd | |||
${NSD_GetState} $hwnd $0 | |||
ShowWindow $passwordControl ${SW_HIDE} | |||
${If} $0 == 1 | |||
SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 0 0 | |||
${Else} | |||
SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 42 0 | |||
${EndIf} | |||
ShowWindow $passwordControl ${SW_SHOW} | |||
FunctionEnd | |||
Section "" | |||
SectionEnd | |||
</highlight-nsis> | |||
'''NOTE''' to re-set the 'fat dot' character seen in the ANSI build when using 'XPStyle on', you cannot use the standard SendMessage (using SendMessageA under the hood) as it is a Unicode character. The System plugin can be used to send a SendMessageW command instead: | |||
<highlight-nsis> | |||
/* 9679 is the fat dot char */ | |||
System::Call "user32::SendMessageW(i $hwnd, i ${EM_SETPASSWORDCHAR}, i 9679, i 0)" | |||
</highlight-nsis> | |||
== How to create a Numbers-only Text control == | == How to create a Numbers-only Text control == | ||
See the [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html nsDialogs] documentation - a | See the [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html nsDialogs] documentation - a Numbers-only control is one of the controls supported by default; ${NSD_CreateNumber} | ||
== How to create a Read-only Text control == | == How to create a Read-only Text control == | ||
The read-only state of a Text control can be set using SendMessage with the [http://social.msdn.microsoft.com/Search/en-US/?Query=win32+EM_SETREADONLY EM_SETREADONLY] flag. | The read-only state of a Text control can be set using [http://nsis.sourceforge.net/Docs/Chapter4.html#4.9.14.10 SendMessage] with the [http://social.msdn.microsoft.com/Search/en-US/?Query=win32+EM_SETREADONLY EM_SETREADONLY] flag. | ||
Note that a read-only Edit (Text) control is ''not'' the same as a disabled Text control. A disabled Text control will display its text grayed out, a read-only Text control remains black on a light grey background. In addition, a disabled multi-line Text control cannot be scrolled. A read-only multi-line Text control, on the other, ''can'' be scrolled. | Note that a read-only Edit (Text) control is ''not'' the same as a disabled Text control. A disabled Text control will display its text grayed out, a read-only Text control remains black on a light grey background. In addition, a disabled multi-line Text control cannot be scrolled. A read-only multi-line Text control, on the other hand, ''can'' be scrolled. | ||
<highlight-nsis> | <highlight-nsis> | ||
Line 197: | Line 313: | ||
</highlight-nsis> | </highlight-nsis> | ||
== How to create two groups of RadioButtons == | == Radio buttons == | ||
Use [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-addstyle ${NSD_AddStyle}] to add the http://social.msdn.microsoft.com/Search/en-US/?Query=win32+WS_GROUP WS_GROUP] style to the first radiobutton of each group. | |||
=== Basic radio button usage === | |||
<highlight-nsis> | |||
!include nsDialogs.nsh | |||
Page Custom MyPageCreate MyPageLeave | |||
Var StationChoice | |||
Function MyPageCreate | |||
nsDialogs::Create 1018 | |||
Pop $0 | |||
${NSD_CreateFirstRadioButton} 0 0 40% 6% "NPR" | |||
Pop $1 | |||
SendMessage $1 ${BM_CLICK} "" "" ; Must select a default | |||
${NSD_CreateAdditionalRadioButton} 0 12% 40% 6% "BBC" | |||
Pop $2 | |||
${IfThen} $StationChoice == "BBC" ${|} SendMessage $2 ${BM_CLICK} "" "" ${|} | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function MyPageLeave | |||
${NSD_GetChecked} $1 $3 | |||
${If} $3 <> ${BST_UNCHECKED} | |||
StrCpy $StationChoice "NPR" | |||
${Else} | |||
StrCpy $StationChoice "BBC" | |||
${EndIf} | |||
FunctionEnd | |||
Section | |||
DetailPrint "Turning the dial to $StationChoice" | |||
SectionEnd | |||
</highlight-nsis> | |||
=== Update page based on radio changes === | |||
<highlight-nsis> | |||
!include nsDialogs.nsh | |||
Page Custom MyPageCreate | |||
Function MyPageCreate | |||
nsDialogs::Create 1018 | |||
Pop $0 | |||
; Group 1 | |||
${NSD_CreateFirstRadioButton} 0 0 50% 12u "NPR" | |||
Pop $1 | |||
${NSD_OnClick} $1 onStationChanged | |||
${NSD_CreateAdditionalRadioButton} 0 14u 50% 12u "BBC" | |||
Pop $2 | |||
${NSD_OnClick} $2 onStationChanged | |||
${NSD_CreateLabel} 0 30u 80% 12u "" | |||
Pop $3 | |||
SendMessage $1 ${BM_CLICK} "" "" ; Must select a default | |||
; Group 2 | |||
${NSD_CreateFirstRadioButton} 0 50u 50% 12u "FM" | |||
Pop $0 ; Demo only, don't need the handle later | |||
${NSD_CreateAdditionalRadioButton} 0 64u 50% 12u "AM" | |||
Pop $0 ; Demo only, don't need the handle later | |||
SendMessage $0 ${BM_CLICK} "" "" ; Must select a default | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function onStationChanged | |||
Pop $0 | |||
${NSD_GetChecked} $1 $0 | |||
${If} $0 <> ${BST_UNCHECKED} | |||
${NSD_SetText} $3 "America, f*(# yeah!" | |||
${Else} | |||
${NSD_SetText} $3 "Keep Calm and Carry On" | |||
${EndIf} | |||
FunctionEnd | |||
</highlight-nsis> | |||
=== How to create two groups of RadioButtons === | |||
Use [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-addstyle ${NSD_AddStyle}] to add the [http://social.msdn.microsoft.com/Search/en-US/?Query=win32+WS_GROUP WS_GROUP] style to the first radiobutton of each group. | |||
In Windows' UI handling, all radiobuttons are considered to be part of the same group if no group starter is defined. | In Windows' UI handling, all radiobuttons are considered to be part of the same group if no group starter is defined. | ||
Line 206: | Line 398: | ||
<highlight-nsis> | <highlight-nsis> | ||
${NSD_AddStyle} $hwnd ${WS_GROUP} # WS_GROUP is defined in winmessages.nsh | ${NSD_AddStyle} $hwnd ${WS_GROUP} # WS_GROUP is defined in winmessages.nsh | ||
</ | </highlight-nsis> | ||
example: | example: | ||
Line 242: | Line 434: | ||
</highlight-nsis> | </highlight-nsis> | ||
== How to easily handle radiobutton selections == | === How to easily handle radiobutton selections === | ||
Often you do not want to specify separate [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#ref-onclick OnClick] functions for each radiobutton... | Often you do not want to specify separate [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#ref-onclick OnClick] functions for each radiobutton... | ||
<highlight-nsis> | <highlight-nsis> | ||
Line 420: | Line 612: | ||
</highlight-nsis> | </highlight-nsis> | ||
== UpDown controls == | |||
=== How to create a typical UpDown control === | |||
The [http://social.msdn.microsoft.com/Search/en-US?query=win32%20updown&ac=8 UpDown control] is not included with nsDialogs by default, but can easily be created by extending nsDialogs' existing control library. | |||
Typical usage of an UpDown control is in conjunction with a number field, a 'buddy' in Windows controls parlance, created immediately prior to the UpDown control, which integrates the UpDown control and automatically updates as the user clicks the up/down arrows, so the below define will be setup for that use. | |||
<highlight-nsis> | |||
!define /math UDM_SETBUDDY ${WM_USER} + 105 | |||
!define /math UDM_SETRANGE32 ${WM_USER} + 111 | |||
!define /math UDM_GETRANGE32 ${WM_USER} + 112 | |||
!define /math UDM_SETPOS32 ${WM_USER} + 113 | |||
!define /math UDM_GETPOS32 ${WM_USER} + 114 | |||
!define UDS_WRAP 0x0001 | |||
!define UDS_SETBUDDYINT 0x0002 | |||
!define UDS_ALIGNRIGHT 0x0004 | |||
!define UDS_ALIGNLEFT 0x0008 | |||
!define UDS_AUTOBUDDY 0x0010 | |||
!define UDS_ARROWKEYS 0x0020 | |||
!define UDS_HORZ 0x0040 | |||
!define UDS_NOTHOUSANDS 0x0080 | |||
!define UDS_HOTTRACK 0x0100 | |||
!define UDN_FIRST -721 | |||
!define /math UDN_DELTAPOS ${UDN_FIRST} - 1 | |||
!define __NSD_UpDown_CLASS msctls_updown32 | |||
!define __NSD_UpDown_STYLE ${WS_CHILD}|${WS_VISIBLE}|${UDS_SETBUDDYINT}|${UDS_ALIGNRIGHT}|${UDS_AUTOBUDDY}|${UDS_ARROWKEYS}|${UDS_NOTHOUSANDS}|${UDS_HOTTRACK} | |||
!define __NSD_UpDown_EXSTYLE 0 | |||
!insertmacro __NSD_DefineControl UpDown | |||
</highlight-nsis> | |||
After including this in your script, you can use ${NSD_CreateUpDown} to create the control. | |||
An example use, presuming you have the above in "nsDialogs_updown.nsh", with the range of the UpDown control limited between 0 and 100, and its current value set to 50. | |||
<highlight-nsis> | |||
!include "nsDialogs.nsh" | |||
!include "nsDialogs_createUpdown.nsh" | |||
OutFile "$%temp%\temp.exe" | |||
var dialog | |||
var hwnd | |||
var null | |||
Page custom Test | |||
Function Test | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateNumber} 0 0 60u 12u "" | |||
Pop $null | |||
${NSD_CreateUpDown} 0 0 0 0 "" | |||
Pop $hwnd | |||
SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max | |||
SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value | |||
nsDialogs::Show | |||
FunctionEnd | |||
Section | |||
SectionEnd | |||
</highlight-nsis> | |||
Note that because of the ${UDS_AUTOBUDDY} style, the Number control will automatically be used as the UpDown control's 'buddy' - the control receiving the value of the UpDown control through ${UDS_SETBUDDYINT}. If for any reason whatsoever you cannot create the control that should be the UpDown control's 'buddy' immediately prior to creating the UpDown control, use the following to set the correct 'buddy'. | |||
<highlight-nsis> | |||
SendMessage $hwndUpDownControl ${UDM_SETBUDDY} $hwndBuddyControl | |||
</highlight-nsis> | |||
Note also that the UpDown control's sizes are all zero. This is because Windows will automatically fit the UpDown arrows within the Number text field - so keep in mind that your Number text field will need some space for the UpDown arrows. | |||
=== How to create a custom-styled UpDown control === | |||
Unfortunately, most of the UpDown control's styles can't be set -after- the UpDown control has been created, meaning you can't use [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-addstyle ${NSD_AddStyle}] to add the style after the fact, and you'd have to either adjust the defines from the typical UpDown control, or create the control manually through [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#ref-createcontrol nsDialogs::CreateControl]. | |||
For example, you may wish to have left/right arrows rather than up/down arrows - and you may wish those separate from the Number text field as otherwise the left/right arrows appear too small. To do this, the ${UDS_ALIGNRIGHT} style needs to be removed, and the ${UDS_HORZ} style added - and, unlike the previous example, the position and size of the UpDown control should be set directly as it won't be integrated with the Number text field 'buddy' anymore: | |||
<highlight-nsis> | |||
Function Test | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateNumber} 0 0 60u 12u "" | |||
Pop $null | |||
nsDialogs::CreateControl msctls_updown32 \ | |||
${DEFAULT_STYLES}|${UDS_SETBUDDYINT}|${UDS_AUTOBUDDY}|${UDS_ARROWKEYS}|${UDS_NOTHOUSANDS}|${UDS_HOTTRACK}|${UDS_HORZ} \ | |||
0 \ | |||
60u 0 20u 12u \ | |||
"" | |||
Pop $hwnd | |||
SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max | |||
SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value | |||
nsDialogs::Show | |||
FunctionEnd | |||
</highlight-nsis> | |||
=== How to detect UpDown control interaction === | |||
You can detect an UpDown control interaction using the [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-onnotify ${NSD_OnNotify}] callback, checking whether the message is ${UDN_DELTAPOS} and then getting the information out of the data packet using the System plugin: | |||
<highlight-nsis> | |||
!include "nsDialogs.nsh" | |||
!include "nsDialogs_createUpdown.nsh" | |||
OutFile "$%temp%\temp.exe" | |||
var dialog | |||
var hwnd | |||
var null | |||
var msg | |||
var nmupdown | |||
Page custom Test | |||
Function Test | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateNumber} 0 0 60u 12u "" | |||
Pop $null | |||
${NSD_CreateUpDown} 0 0 0 0 "" | |||
Pop $hwnd | |||
${NSD_OnNotify} $hwnd updown.onnotify | |||
SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max | |||
SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function updown.onnotify | |||
Pop $hwnd | |||
Pop $msg | |||
Pop $nmupdown | |||
${If} $msg = ${UDN_DELTAPOS} | |||
System::Call "*$nmupdown(i, i, i, i.r0, i.r1)" | |||
; $0 = current value | |||
; $1 = value that will be added (may be negative) | |||
IntOp $2 $0 + $1 | |||
; $2 = new value | |||
MessageBox MB_OK "[$0]+[$1]=[$2]" | |||
${EndIf} | |||
FunctionEnd | |||
Section | |||
SectionEnd | |||
</highlight-nsis> | |||
== Progress bars == | |||
=== How to Control a Progress Bar control (using absolute values) === | |||
You can control a Progress Bar using sendMessage and the [http://msdn.microsoft.com/en-us/library/bb760818%28VS.85%29.aspx messages for Progress Bar controls]. These are _almost all_ defined in the WinMessages.nsh header that comes with NSIS, so be sure to include this header. | |||
There is at least one exception, which is very useful to define yourself because it cuts down on code and makes your source more easily readable, and that is [http://social.msdn.microsoft.com/Search/en-US?query=PBM_SETRANGE32 PBM_SETRANGE32]. PBM_SETRANGE32 allows you to set the start and end range as simply two numbers, instead of having to use ${MakeLong} from WinDef.nsh as required by PBM_SETRANGE | |||
<highlight-nsis> | |||
!define /math PBM_SETRANGE32 ${WM_USER} + 6 | |||
</highlight-nsis> | |||
In order to update the Progress Bar's value, you'll need to use an nsDialogs timer to invoke a function that handles your actual processing. This timer is only invoked once. | |||
Here's a simple example that creates a Progress Bar that has a 0 (zero) to 100 range for a typical full percentage increase, and sets the progress to 25%, 50%, 75% and 100%, using the Sleep command to simulate processing occurring - normally this might be other NSIS calls or calling external applications/installers before your main installation, etc. | |||
<highlight-nsis> | |||
!include "WinMessages.nsh" | |||
!include "MUI2.nsh" | |||
!include "nsDialogs.nsh" | |||
OutFile "test.exe" | |||
Section | |||
SectionEnd | |||
Var dialog | |||
Var hwnd | |||
Var null | |||
!define /math PBM_SETRANGE32 ${WM_USER} + 6 | |||
Page Custom page.custom | |||
Function page.custom | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateProgressBar} 0 0 100% 10% "Test" | |||
Pop $hwnd | |||
${NSD_CreateTimer} NSD_Timer.Callback 10 | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function NSD_Timer.Callback | |||
${NSD_KillTimer} NSD_Timer.Callback | |||
SendMessage $hwnd ${PBM_SETRANGE32} 0 100 | |||
SendMessage $hwnd ${PBM_SETPOS} 25 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 50 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 75 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 100 0 | |||
FunctionEnd | |||
!insertmacro MUI_LANGUAGE "English" | |||
</highlight-nsis> | |||
=== How to Control a Progress Bar control (using step values) === | |||
One of the down sides of the previous example is that you always have to keep track of your percentages, when those percentages might not even be important, as long as the user knows there -is- progress. | |||
An example where keeping track of your percentages could become problematic is with copy/pasting chunks of code. You might suddenly find yourself with a progress bar that goes from 0% to 50% back to 25% and then up to 75%. | |||
One pretty simple solution to this is to use a stepped progress bar instead. This method lets you define a step increment value, and simply call a step function to always increment the progress bar by that value. Here is an example using this method, which is functionally the same as the previous example. Note that we're setting the range to the number of steps we're expecting in our function. | |||
<highlight-nsis> | |||
!include "WinMessages.nsh" | |||
!include "MUI2.nsh" | |||
!include "nsDialogs.nsh" | |||
OutFile "test.exe" | |||
Section | |||
SectionEnd | |||
Var dialog | |||
Var hwnd | |||
Var null | |||
!define /math PBM_SETRANGE32 ${WM_USER} + 6 | |||
Page Custom page.custom | |||
Function page.custom | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateProgressBar} 0 0 100% 10% "Test" | |||
Pop $hwnd | |||
${NSD_CreateTimer} NSD_Timer.Callback 10 | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function NSD_Timer.Callback | |||
${NSD_KillTimer} NSD_Timer.Callback | |||
SendMessage $hwnd ${PBM_SETRANGE32} 0 4 | |||
SendMessage $hwnd ${PBM_SETSTEP} 1 0 | |||
SendMessage $hwnd ${PBM_STEPIT} 0 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_STEPIT} 0 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_STEPIT} 0 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_STEPIT} 0 0 | |||
SendMessage $hwnd ${PBM_SETPOS} 4 0 | |||
FunctionEnd | |||
!insertmacro MUI_LANGUAGE "English" | |||
</highlight-nsis> | |||
Note that at the end, we still set the progress to 100%. The reason for this is that you might have some conditional steps in your function. If you forget to step the progress, then the progress value will fall short of 100%. This is an oft-reported user interface issue, where the user complains that even though the process is complete, the progress bar is stuck at less than 100%. | |||
You'll still have to take care to not use -more- steps than you have specified in the PBM_SETRANGE32 call, as any steps after that will just show 100% without any apparent progress. | |||
=== How to Create a Marquee (endless loop) Progress Bar control === | |||
Sometimes you might not know anything about progress - for example, you're simply executing a task that may take some time but there's no way to tell how far along that task you are. | |||
In that case you might want to use a so-called Marquee progress bar that simply loops from left to right endlessly. | |||
There is one caveat to this: You can't use a Marquee progress bar unless you use an interface that uses XP styles (see also [http://nsis.sourceforge.net/Docs/Chapter4.html#4.8.1.46 XPStyle]). | |||
Other than that, it's smooth sailing by using [http://nsis.sourceforge.net/Docs/nsDialogs/Readme.html#mref-addstyle ${NSD_AddStyle}] to add the [http://social.msdn.microsoft.com/Search/en-US/?Query=win32+PBS_MARQUEE PBS_MARQUEE] style to the progress bar. | |||
Here's an example of doing exactly that: | |||
<highlight-nsis> | |||
!include "WinMessages.nsh" | |||
!include "MUI2.nsh" | |||
!include "nsDialogs.nsh" | |||
OutFile "test.exe" | |||
Section | |||
SectionEnd | |||
Var dialog | |||
Var hwnd | |||
Var null | |||
!define PBS_MARQUEE 0x08 | |||
Page Custom page.custom | |||
Function page.custom | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
${NSD_CreateProgressBar} 0 0 100% 10% "Test" | |||
Pop $hwnd | |||
${NSD_AddStyle} $hwnd ${PBS_MARQUEE} | |||
${NSD_CreateTimer} NSD_Timer.Callback 10 | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function NSD_Timer.Callback | |||
${NSD_KillTimer} NSD_Timer.Callback ; Kill the timer | |||
SendMessage $hwnd ${PBM_SETMARQUEE} 1 50 ; start=1|stop=0 interval(ms)=+N | |||
_again: | |||
MessageBox MB_YESNO "Stop the marquee?" IDNO _again | |||
SendMessage $hwnd ${PBM_SETMARQUEE} 0 0 | |||
FunctionEnd | |||
!insertmacro MUI_LANGUAGE "English" | |||
</highlight-nsis> | |||
Note that a Marquee Progress Bar always runs from left to right - you can't set it to any other position. | |||
=== How to Create a Smooth Progress Bar control === | |||
A Smooth Progress Bar is one that is not cut up into small rectangles - i.e. the entire progress is one solid, smooth, bar. | |||
Unfortunately, there are two caveats in this case: | |||
1. The standard Progress Bar is styled by XP styles which override this style. For the same reason you can't have a Marquee progress bar _without_ XP Styles, you can't have a Smooth progress bar _with_ XP Styles (see also [http://nsis.sourceforge.net/Docs/Chapter4.html#4.8.1.46 XPStyle]). | |||
2. The Smooth style ([http://social.msdn.microsoft.com/Search/en-US?query=PBS_SMOOTH PBS_SMOOTH]) can't be added -after- the control has been created by nsDialogs. So you have to create it with that style already set. | |||
Below is an example that uses a Smooth Progress Bar, with XP Styles off. | |||
<highlight-nsis> | |||
!include "WinMessages.nsh" | |||
!include "MUI2.nsh" | |||
!include "nsDialogs.nsh" | |||
OutFile "test.exe" | |||
Section | |||
SectionEnd | |||
Var dialog | |||
Var hwnd | |||
Var null | |||
!define PB_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE} | |||
!define PBS_SMOOTH 0x01 | |||
!define /math PBM_SETRANGE32 ${WM_USER} + 6 | |||
Page Custom page.custom | |||
Function page.custom | |||
nsDialogs::Create 1018 | |||
Pop $dialog | |||
nsDialogs::CreateControl "msctls_progress32" \ | |||
${DEFAULT_STYLES}|${PBS_SMOOTH} \ | |||
${PB_EXSTYLE} \ | |||
0 0 100% 10% \ | |||
"Test" \ | |||
Pop $hwnd | |||
${NSD_CreateTimer} NSD_Timer.Callback 10 | |||
nsDialogs::Show | |||
FunctionEnd | |||
Function NSD_Timer.Callback | |||
${NSD_KillTimer} NSD_Timer.Callback ; Kill the timer | |||
SendMessage $hwnd ${PBM_SETRANGE32} 0 100 | |||
SendMessage $hwnd ${PBM_SETPOS} 25 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 50 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 75 0 | |||
Sleep 2000 | |||
SendMessage $hwnd ${PBM_SETPOS} 100 0 | |||
FunctionEnd | |||
!insertmacro MUI_LANGUAGE "English" | |||
XPStyle off | |||
</highlight-nsis> | |||
== How to let controls receive Hotkey (alt+letter) combinations == | |||
Only controls that have labels can be assigned a hotkey, simply by including an ampersand in its title. E.g. | |||
<highlight-nsis> | |||
${NSD_CreateCheckbox} 3% 3% 20% 8% "The hot&key here is alt+k" | |||
</highlight-nsis> | |||
However, when the page is first navigated to in NSIS, the NSIS dialog is what has focus, rather than the inner nsDialogs dialog. So set focus to the nsDialogs dialog before you tell nsDialogs to show it: | |||
<highlight-nsis> | |||
nsDialogs::Create 1018 | |||
Pop $dialog ; assuming you have a 'dialog' variable! | |||
; further code here | |||
SendMessage $dialog ${WM_SETFOCUS} $HWNDPARENT 0 | |||
nsDialogs::Show | |||
</highlight-nsis> | |||
The NSIS dialog will still handle e.g. alt+N for the Next button as the hotkey event simply 'bubbles up' to the parent window if window with current focus does not react to it. | |||
( Hint: That means you shouldn't set any hotkeys for the B(ack) or N(ext) letters! ) | |||
Using these methods, you can easily create an installer that can be navigated entirely and easily by keyboard-only. | |||
== How to create a sorted droplist control == | |||
Sometimes you may have to display a dropdown list with sorted information - for example, a list of folders or files (retrieved through one of the many filesearch scripts) that may not have come in sorted. | |||
One solution would be to pre-sort the results using a sorting script or the [[Arrays in NSIS|Array]] plugin. | |||
Another solution is to use a dropdown list which has a 'sorted' style, [http://msdn.microsoft.com/en-us/library/7h63bxbe%28VS.80%29.aspx CBS_SORT], set on it so that its listings are automatically sorted. | |||
Unfortunately this is not a style you can not add after the control has been created, so you have to create it yourself. | |||
Below is a header file I wrote for use in our installer which lets us use the same syntax as nsDialogs uses for other controls. | |||
<highlight-nsis> | |||
/* | |||
nsDialogs_createDroplistSorted.nsh | |||
Header file for creating a sorted droplist control. | |||
Usage: | |||
${NSD_CreateDroplistSorted} left top width height "" | |||
Creates the sorted droplist at the location specified. | |||
*/ | |||
!ifndef NSDIALOGS_createDroplistSorted_INCLUDED | |||
!define NSDIALOGS_createDroplistSorted_INCLUDED | |||
!verbose push | |||
!verbose 3 | |||
!include WinMessages.nsh | |||
!define __NSD_DropListSorted_CLASS COMBOBOX | |||
!define __NSD_DropListSorted_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${WS_VSCROLL}|${WS_CLIPCHILDREN}|${CBS_AUTOHSCROLL}|${CBS_HASSTRINGS}|${CBS_DROPDOWNLIST}|${CBS_SORT} | |||
!define __NSD_DropListSorted_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE} | |||
!insertmacro __NSD_DefineControl DropListSorted | |||
!verbose pop | |||
!endif | |||
</highlight-nsis> | |||
[[Category:Code Examples]] [[Category:nsDialogs Examples]] | [[Category:Code Examples]] [[Category:nsDialogs Examples]] [[Category:Plug-ins FAQ]] |
Latest revision as of 13:13, 4 August 2021
How to Enable/Disable a control
Use the standard NSIS EnableWindow command.
NSDialogs lets you pop the hwnd of a control created via ${NSD_Create*}. EnableWindow takes a hwnd as one of its parameters. With this, you can easily enable/disable a control.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd var button Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateCheckbox} 0 0 50% 6% "Enable button below" Pop $hwnd ${NSD_OnClick} $hwnd EnDisableButton ${NSD_CreateButton} 25% 25% 50% 50% "Hello World" Pop $button EnableWindow $button 0 # start out disabled nsDialogs::Show FunctionEnd Function EnDisableButton Pop $hwnd ${NSD_GetState} $hwnd $0 ${If} $0 == 1 EnableWindow $button 1 ${Else} EnableWindow $button 0 ${EndIf} FunctionEnd Section "" SectionEnd
How to Show/Hide a control
Use the standard NSIS ShowWindow command.
NSDialogs lets you pop the hwnd of a control created via ${NSD_Create*}. ShowWindow takes a hwnd as one of its parameters. With this, you can easily show/hide a control.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd var button Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateCheckbox} 0 0 50% 6% "Show button below" Pop $hwnd ${NSD_OnClick} $hwnd EnDisableButton ${NSD_CreateButton} 25% 25% 50% 50% "Hello World" Pop $button ShowWindow $button ${SW_HIDE} # start out hidden nsDialogs::Show FunctionEnd Function EnDisableButton Pop $hwnd ${NSD_GetState} $hwnd $0 ${If} $0 == 1 ShowWindow $button ${SW_SHOW} ${Else} ShowWindow $button ${SW_HIDE} ${EndIf} FunctionEnd Section "" SectionEnd
How to create a label with center-aligned text
Center-aligned text - where the text is always centered within the control, no matter its size, is often useful for presentation purposes. Making a label's text center-aligned is simple, using ${NSD_AddStyle} add the ${SS_CENTER} style.
!include "nsDialogs.nsh" OutFile "$%temp%\temp.exe" var dialog var hwnd var null Page custom Test Function Test nsDialogs::Create 1018 Pop $dialog ${NSD_CreateLabel} 0 0 100% 20% "This line will be centered.$\nAnd so will this line." Pop $hwnd ${NSD_AddStyle} $hwnd ${SS_CENTER} nsDialogs::Show FunctionEnd Section SectionEnd
How to create a multi-line edit (text) control
Although multi-line is a Style of a control, for Edit (Text) controls it is one of few styles that cannot be set once the control has already been created - so you can't use ${NSD_AddStyle}.
Instead, you will have to create the control manually:
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateText} 0 0 100% 40% "This is NOT a$\r$\nmulti-line$\r$\nedit control" Pop $hwnd nsDialogs::CreateControl EDIT \ "${__NSD_Text_STYLE}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN}" \ "${__NSD_Text_EXSTYLE}" \ 0 50% 100% 40% \ "This IS a$\r$\nmulti-line$\r$\nedit control" Pop $hwnd nsDialogs::Show FunctionEnd Section "" SectionEnd
Or, much cleaner, using the NsDialogs_CreateTextMultiline header:
!include "nsDialogs.nsh" !include "nsDialogs_createTextMultiline.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateText} 0 0 100% 40% "This is NOT a$\r$\nmulti-line$\r$\nedit control" Pop $hwnd ${NSD_CreateTextMultiline} 0 50% 100% 40% "This IS a$\r$\nmulti-line$\r$\nedit control" Pop $hwnd nsDialogs::Show FunctionEnd Section "" SectionEnd
How to create a Text Password control
See the nsDialogs documentation - a Password control is one of the controls supported by default; ${NSD_CreatePassword}
How to set the character used by a Text Password control
By default a Text Password control will use asterisks (*****) with 'XPStyle off', or fat dots with 'XPStyle on' as the password characters to mask the text. You can change this character using SendMessage with the EM_SETPASSWORDCHAR flag.
The password character is identified by its ASCII or UNICODE index; keep in mind that the font you use for your installer may not support the character you wish to use.
NOTE If you set the password character to 0 (zero), the text will not be masked! You can use this to toggle between the text being visible and masked. See also the How to hide/show passwords in a Text Password control entry.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreatePassword} 0 0 50% 8% "This is a password field" Pop $hwnd SendMessage $hwnd ${EM_SETPASSWORDCHAR} 149 0 # 149 = medium dot nsDialogs::Show FunctionEnd Section "" SectionEnd
How to hide/show passwords in a Text Password control
By using SendMessage with the EM_SETPASSWORDCHAR flag, specifying the character as 0 (zero), you can make a password visible, and invisible again by specifying a non-zero character.
See also the How to set the character used by a Text Password control entry.
NOTE The Password control has to be forcibly redrawn after changing the mask character. This is done by hiding and then showing the control using ShowWindow.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd var passwordControl Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateCheckbox} 0 0 25% 8% "Show password" Pop $hwnd ${NSD_OnClick} $hwnd ShowPassword ${NSD_CreatePassword} 0 10% 50% 8% "This is a password field" Pop $passwordControl nsDialogs::Show FunctionEnd Function ShowPassword Pop $hwnd ${NSD_GetState} $hwnd $0 ShowWindow $passwordControl ${SW_HIDE} ${If} $0 == 1 SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 0 0 ${Else} SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 42 0 ${EndIf} ShowWindow $passwordControl ${SW_SHOW} FunctionEnd Section "" SectionEnd
NOTE to re-set the 'fat dot' character seen in the ANSI build when using 'XPStyle on', you cannot use the standard SendMessage (using SendMessageA under the hood) as it is a Unicode character. The System plugin can be used to send a SendMessageW command instead:
/* 9679 is the fat dot char */ System::Call "user32::SendMessageW(i $hwnd, i ${EM_SETPASSWORDCHAR}, i 9679, i 0)"
How to create a Numbers-only Text control
See the nsDialogs documentation - a Numbers-only control is one of the controls supported by default; ${NSD_CreateNumber}
How to create a Read-only Text control
The read-only state of a Text control can be set using SendMessage with the EM_SETREADONLY flag.
Note that a read-only Edit (Text) control is not the same as a disabled Text control. A disabled Text control will display its text grayed out, a read-only Text control remains black on a light grey background. In addition, a disabled multi-line Text control cannot be scrolled. A read-only multi-line Text control, on the other hand, can be scrolled.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd var textControl Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateCheckBox} 0 0 50% 6% "Set text field below read-only" Pop $hwnd ${NSD_OnClick} $hwnd SetReadonly ${NSD_CreateText} 0 12% 100% 8% "Hello World" Pop $textControl nsDialogs::Show FunctionEnd Function SetReadonly Pop $hwnd ${NSD_GetState} $hwnd $0 SendMessage $textControl ${EM_SETREADONLY} $0 0 FunctionEnd Section "" SectionEnd
Radio buttons
Basic radio button usage
!include nsDialogs.nsh Page Custom MyPageCreate MyPageLeave Var StationChoice Function MyPageCreate nsDialogs::Create 1018 Pop $0 ${NSD_CreateFirstRadioButton} 0 0 40% 6% "NPR" Pop $1 SendMessage $1 ${BM_CLICK} "" "" ; Must select a default ${NSD_CreateAdditionalRadioButton} 0 12% 40% 6% "BBC" Pop $2 ${IfThen} $StationChoice == "BBC" ${|} SendMessage $2 ${BM_CLICK} "" "" ${|} nsDialogs::Show FunctionEnd Function MyPageLeave ${NSD_GetChecked} $1 $3 ${If} $3 <> ${BST_UNCHECKED} StrCpy $StationChoice "NPR" ${Else} StrCpy $StationChoice "BBC" ${EndIf} FunctionEnd Section DetailPrint "Turning the dial to $StationChoice" SectionEnd
Update page based on radio changes
!include nsDialogs.nsh Page Custom MyPageCreate Function MyPageCreate nsDialogs::Create 1018 Pop $0 ; Group 1 ${NSD_CreateFirstRadioButton} 0 0 50% 12u "NPR" Pop $1 ${NSD_OnClick} $1 onStationChanged ${NSD_CreateAdditionalRadioButton} 0 14u 50% 12u "BBC" Pop $2 ${NSD_OnClick} $2 onStationChanged ${NSD_CreateLabel} 0 30u 80% 12u "" Pop $3 SendMessage $1 ${BM_CLICK} "" "" ; Must select a default ; Group 2 ${NSD_CreateFirstRadioButton} 0 50u 50% 12u "FM" Pop $0 ; Demo only, don't need the handle later ${NSD_CreateAdditionalRadioButton} 0 64u 50% 12u "AM" Pop $0 ; Demo only, don't need the handle later SendMessage $0 ${BM_CLICK} "" "" ; Must select a default nsDialogs::Show FunctionEnd Function onStationChanged Pop $0 ${NSD_GetChecked} $1 $0 ${If} $0 <> ${BST_UNCHECKED} ${NSD_SetText} $3 "America, f*(# yeah!" ${Else} ${NSD_SetText} $3 "Keep Calm and Carry On" ${EndIf} FunctionEnd
How to create two groups of RadioButtons
Use ${NSD_AddStyle} to add the WS_GROUP style to the first radiobutton of each group. In Windows' UI handling, all radiobuttons are considered to be part of the same group if no group starter is defined.
Therefore, to have two radiobutton groups of two radiobuttons each, you must specify a group starter for each, otherwise the third and fourth radiobuttons will be considered part of the first group.
Setting a group starter is easy using ${NSD_AddStyle}, use:
${NSD_AddStyle} $hwnd ${WS_GROUP} # WS_GROUP is defined in winmessages.nsh
example:
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateRadioButton} 0 0 40% 6% "Group 1, Radio 1" Pop $hwnd ${NSD_AddStyle} $hwnd ${WS_GROUP} ${NSD_CreateRadioButton} 0 12% 40% 6% "Group 1, Radio 2" Pop $hwnd ${NSD_CreateRadioButton} 50% 0 40% 6% "Group 2, Radio 1" Pop $hwnd ${NSD_AddStyle} $hwnd ${WS_GROUP} ${NSD_CreateRadioButton} 50% 12% 40% 6% "Group 2, Radio 2" Pop $hwnd nsDialogs::Show FunctionEnd Section "" SectionEnd
How to easily handle radiobutton selections
Often you do not want to specify separate OnClick functions for each radiobutton...
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateRadioButton} 0 0 40% 6% "Group 1, Radio 1" Pop $hwnd ${NSD_AddStyle} $hwnd ${WS_GROUP} ${NSD_OnClick} $hwnd Group1Radio1Click ${NSD_CreateRadioButton} 0 12% 40% 6% "Group 1, Radio 2" Pop $hwnd ${NSD_OnClick} $hwnd Group1Radio2Click nsDialogs::Show FunctionEnd Function Group1Radio1Click Pop $hwnd MessageBox MB_OK "onClick:Group1Radio1" FunctionEnd Function Group1Radio2Click Pop $hwnd MessageBox MB_OK "onClick:Group1Radio2" FunctionEnd Section "" SectionEnd
But the only obvious alternative seems to be to place each in a different variable and comparing the hwnd on the stack when the callback function is called to that variable.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd var Group1Radio1 var Group1Radio2 Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateRadioButton} 0 0 40% 6% "Group 1, Radio 1" Pop $Group1Radio1 ${NSD_AddStyle} $Group1Radio1 ${WS_GROUP} ${NSD_OnClick} $Group1Radio1 RadioClick ${NSD_CreateRadioButton} 0 12% 40% 6% "Group 1, Radio 2" Pop $Group1Radio2 ${NSD_OnClick} $Group1Radio2 RadioClick nsDialogs::Show FunctionEnd Function RadioClick Pop $hwnd ${If} $hwnd == $Group1Radio1 MessageBox MB_OK "onClick:Group1Radio1" ${ElseIf} $hwnd == $Group1Radio2 MessageBox MB_OK "onClick:Group1Radio2" ${EndIf} FunctionEnd Section "" SectionEnd
However, you can eliminate both by making use of the getUserData and setUserData commands of nsDialogs. Using these *UserData commands, you can store data in a control and easily retrieve this later.
To simplify the use of these commands, we'll be using the header from NsDialogs UserData.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre var dialog var hwnd Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateRadioButton} 0 0 40% 6% "Group 1, Radio 1" Pop $hwnd ${NSD_AddStyle} $hwnd ${WS_GROUP} ${NSD_SetUserData} $hwnd "Group1Radio1" ${NSD_OnClick} $hwnd RadioClick ${NSD_CreateRadioButton} 0 12% 40% 6% "Group 1, Radio 2" Pop $hwnd ${NSD_SetUserData} $hwnd "Group1Radio2" ${NSD_OnClick} $hwnd RadioClick nsDialogs::Show FunctionEnd Function RadioClick Pop $hwnd ${NSD_GetUserData} $hwnd $0 ${If} $0 == "Group1Radio1" MessageBox MB_OK "onClick:Group1Radio1" ${ElseIf} $0 == "Group1Radio2" MessageBox MB_OK "onClick:Group1Radio2" ${EndIf} FunctionEnd Section "" SectionEnd
Using this method, you can easily set a variable to an internal string stored on the radiobutton control without any If-ElseIf-EndIf or Case selections in the OnClick event function at all.
!include "nsDialogs.nsh" !include "winmessages.nsh" !include "logiclib.nsh" OutFile "test.exe" Page Custom pre post var dialog var hwnd var minor Function pre nsDialogs::Create 1018 Pop $dialog ${NSD_CreateRadioButton} 0 0 40% 6% "I am 14 years of age or older" Pop $hwnd ${NSD_AddStyle} $hwnd ${WS_GROUP} ${NSD_SetUserData} $hwnd "false" ${NSD_OnClick} $hwnd RadioClick ${NSD_CreateRadioButton} 0 12% 40% 6% "I am younger than 14 of age" Pop $hwnd ${NSD_SetUserData} $hwnd "true" ${NSD_OnClick} $hwnd RadioClick nsDialogs::Show FunctionEnd Function RadioClick Pop $hwnd ${NSD_GetUserData} $hwnd $minor FunctionEnd Function post ${If} $minor == "" MessageBox MB_OK "Please specify your age group" Abort ${ElseIf} $minor == true MessageBox MB_OK "installation will continue with content appropriate for your age" ${Else} MessageBox MB_OK "installation will continue normally" ${EndIf} FunctionEnd Section "" SectionEnd
UpDown controls
How to create a typical UpDown control
The UpDown control is not included with nsDialogs by default, but can easily be created by extending nsDialogs' existing control library.
Typical usage of an UpDown control is in conjunction with a number field, a 'buddy' in Windows controls parlance, created immediately prior to the UpDown control, which integrates the UpDown control and automatically updates as the user clicks the up/down arrows, so the below define will be setup for that use.
!define /math UDM_SETBUDDY ${WM_USER} + 105 !define /math UDM_SETRANGE32 ${WM_USER} + 111 !define /math UDM_GETRANGE32 ${WM_USER} + 112 !define /math UDM_SETPOS32 ${WM_USER} + 113 !define /math UDM_GETPOS32 ${WM_USER} + 114 !define UDS_WRAP 0x0001 !define UDS_SETBUDDYINT 0x0002 !define UDS_ALIGNRIGHT 0x0004 !define UDS_ALIGNLEFT 0x0008 !define UDS_AUTOBUDDY 0x0010 !define UDS_ARROWKEYS 0x0020 !define UDS_HORZ 0x0040 !define UDS_NOTHOUSANDS 0x0080 !define UDS_HOTTRACK 0x0100 !define UDN_FIRST -721 !define /math UDN_DELTAPOS ${UDN_FIRST} - 1 !define __NSD_UpDown_CLASS msctls_updown32 !define __NSD_UpDown_STYLE ${WS_CHILD}|${WS_VISIBLE}|${UDS_SETBUDDYINT}|${UDS_ALIGNRIGHT}|${UDS_AUTOBUDDY}|${UDS_ARROWKEYS}|${UDS_NOTHOUSANDS}|${UDS_HOTTRACK} !define __NSD_UpDown_EXSTYLE 0 !insertmacro __NSD_DefineControl UpDown
After including this in your script, you can use ${NSD_CreateUpDown} to create the control.
An example use, presuming you have the above in "nsDialogs_updown.nsh", with the range of the UpDown control limited between 0 and 100, and its current value set to 50.
!include "nsDialogs.nsh" !include "nsDialogs_createUpdown.nsh" OutFile "$%temp%\temp.exe" var dialog var hwnd var null Page custom Test Function Test nsDialogs::Create 1018 Pop $dialog ${NSD_CreateNumber} 0 0 60u 12u "" Pop $null ${NSD_CreateUpDown} 0 0 0 0 "" Pop $hwnd SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value nsDialogs::Show FunctionEnd Section SectionEnd
Note that because of the ${UDS_AUTOBUDDY} style, the Number control will automatically be used as the UpDown control's 'buddy' - the control receiving the value of the UpDown control through ${UDS_SETBUDDYINT}. If for any reason whatsoever you cannot create the control that should be the UpDown control's 'buddy' immediately prior to creating the UpDown control, use the following to set the correct 'buddy'.
SendMessage $hwndUpDownControl ${UDM_SETBUDDY} $hwndBuddyControl
Note also that the UpDown control's sizes are all zero. This is because Windows will automatically fit the UpDown arrows within the Number text field - so keep in mind that your Number text field will need some space for the UpDown arrows.
How to create a custom-styled UpDown control
Unfortunately, most of the UpDown control's styles can't be set -after- the UpDown control has been created, meaning you can't use ${NSD_AddStyle} to add the style after the fact, and you'd have to either adjust the defines from the typical UpDown control, or create the control manually through nsDialogs::CreateControl.
For example, you may wish to have left/right arrows rather than up/down arrows - and you may wish those separate from the Number text field as otherwise the left/right arrows appear too small. To do this, the ${UDS_ALIGNRIGHT} style needs to be removed, and the ${UDS_HORZ} style added - and, unlike the previous example, the position and size of the UpDown control should be set directly as it won't be integrated with the Number text field 'buddy' anymore:
Function Test nsDialogs::Create 1018 Pop $dialog ${NSD_CreateNumber} 0 0 60u 12u "" Pop $null nsDialogs::CreateControl msctls_updown32 \ ${DEFAULT_STYLES}|${UDS_SETBUDDYINT}|${UDS_AUTOBUDDY}|${UDS_ARROWKEYS}|${UDS_NOTHOUSANDS}|${UDS_HOTTRACK}|${UDS_HORZ} \ 0 \ 60u 0 20u 12u \ "" Pop $hwnd SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value nsDialogs::Show FunctionEnd
How to detect UpDown control interaction
You can detect an UpDown control interaction using the ${NSD_OnNotify} callback, checking whether the message is ${UDN_DELTAPOS} and then getting the information out of the data packet using the System plugin:
!include "nsDialogs.nsh" !include "nsDialogs_createUpdown.nsh" OutFile "$%temp%\temp.exe" var dialog var hwnd var null var msg var nmupdown Page custom Test Function Test nsDialogs::Create 1018 Pop $dialog ${NSD_CreateNumber} 0 0 60u 12u "" Pop $null ${NSD_CreateUpDown} 0 0 0 0 "" Pop $hwnd ${NSD_OnNotify} $hwnd updown.onnotify SendMessage $hwnd ${UDM_SETRANGE32} 0 100000 ; min max SendMessage $hwnd ${UDM_SETPOS32} 0 50000 ; 0 value nsDialogs::Show FunctionEnd Function updown.onnotify Pop $hwnd Pop $msg Pop $nmupdown ${If} $msg = ${UDN_DELTAPOS} System::Call "*$nmupdown(i, i, i, i.r0, i.r1)" ; $0 = current value ; $1 = value that will be added (may be negative) IntOp $2 $0 + $1 ; $2 = new value MessageBox MB_OK "[$0]+[$1]=[$2]" ${EndIf} FunctionEnd Section SectionEnd
Progress bars
How to Control a Progress Bar control (using absolute values)
You can control a Progress Bar using sendMessage and the messages for Progress Bar controls. These are _almost all_ defined in the WinMessages.nsh header that comes with NSIS, so be sure to include this header.
There is at least one exception, which is very useful to define yourself because it cuts down on code and makes your source more easily readable, and that is PBM_SETRANGE32. PBM_SETRANGE32 allows you to set the start and end range as simply two numbers, instead of having to use ${MakeLong} from WinDef.nsh as required by PBM_SETRANGE
!define /math PBM_SETRANGE32 ${WM_USER} + 6
In order to update the Progress Bar's value, you'll need to use an nsDialogs timer to invoke a function that handles your actual processing. This timer is only invoked once.
Here's a simple example that creates a Progress Bar that has a 0 (zero) to 100 range for a typical full percentage increase, and sets the progress to 25%, 50%, 75% and 100%, using the Sleep command to simulate processing occurring - normally this might be other NSIS calls or calling external applications/installers before your main installation, etc.
!include "WinMessages.nsh" !include "MUI2.nsh" !include "nsDialogs.nsh" OutFile "test.exe" Section SectionEnd Var dialog Var hwnd Var null !define /math PBM_SETRANGE32 ${WM_USER} + 6 Page Custom page.custom Function page.custom nsDialogs::Create 1018 Pop $dialog ${NSD_CreateProgressBar} 0 0 100% 10% "Test" Pop $hwnd ${NSD_CreateTimer} NSD_Timer.Callback 10 nsDialogs::Show FunctionEnd Function NSD_Timer.Callback ${NSD_KillTimer} NSD_Timer.Callback SendMessage $hwnd ${PBM_SETRANGE32} 0 100 SendMessage $hwnd ${PBM_SETPOS} 25 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 50 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 75 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 100 0 FunctionEnd !insertmacro MUI_LANGUAGE "English"
How to Control a Progress Bar control (using step values)
One of the down sides of the previous example is that you always have to keep track of your percentages, when those percentages might not even be important, as long as the user knows there -is- progress. An example where keeping track of your percentages could become problematic is with copy/pasting chunks of code. You might suddenly find yourself with a progress bar that goes from 0% to 50% back to 25% and then up to 75%.
One pretty simple solution to this is to use a stepped progress bar instead. This method lets you define a step increment value, and simply call a step function to always increment the progress bar by that value. Here is an example using this method, which is functionally the same as the previous example. Note that we're setting the range to the number of steps we're expecting in our function.
!include "WinMessages.nsh" !include "MUI2.nsh" !include "nsDialogs.nsh" OutFile "test.exe" Section SectionEnd Var dialog Var hwnd Var null !define /math PBM_SETRANGE32 ${WM_USER} + 6 Page Custom page.custom Function page.custom nsDialogs::Create 1018 Pop $dialog ${NSD_CreateProgressBar} 0 0 100% 10% "Test" Pop $hwnd ${NSD_CreateTimer} NSD_Timer.Callback 10 nsDialogs::Show FunctionEnd Function NSD_Timer.Callback ${NSD_KillTimer} NSD_Timer.Callback SendMessage $hwnd ${PBM_SETRANGE32} 0 4 SendMessage $hwnd ${PBM_SETSTEP} 1 0 SendMessage $hwnd ${PBM_STEPIT} 0 0 Sleep 2000 SendMessage $hwnd ${PBM_STEPIT} 0 0 Sleep 2000 SendMessage $hwnd ${PBM_STEPIT} 0 0 Sleep 2000 SendMessage $hwnd ${PBM_STEPIT} 0 0 SendMessage $hwnd ${PBM_SETPOS} 4 0 FunctionEnd !insertmacro MUI_LANGUAGE "English"
Note that at the end, we still set the progress to 100%. The reason for this is that you might have some conditional steps in your function. If you forget to step the progress, then the progress value will fall short of 100%. This is an oft-reported user interface issue, where the user complains that even though the process is complete, the progress bar is stuck at less than 100%.
You'll still have to take care to not use -more- steps than you have specified in the PBM_SETRANGE32 call, as any steps after that will just show 100% without any apparent progress.
How to Create a Marquee (endless loop) Progress Bar control
Sometimes you might not know anything about progress - for example, you're simply executing a task that may take some time but there's no way to tell how far along that task you are. In that case you might want to use a so-called Marquee progress bar that simply loops from left to right endlessly.
There is one caveat to this: You can't use a Marquee progress bar unless you use an interface that uses XP styles (see also XPStyle).
Other than that, it's smooth sailing by using ${NSD_AddStyle} to add the PBS_MARQUEE style to the progress bar.
Here's an example of doing exactly that:
!include "WinMessages.nsh" !include "MUI2.nsh" !include "nsDialogs.nsh" OutFile "test.exe" Section SectionEnd Var dialog Var hwnd Var null !define PBS_MARQUEE 0x08 Page Custom page.custom Function page.custom nsDialogs::Create 1018 Pop $dialog ${NSD_CreateProgressBar} 0 0 100% 10% "Test" Pop $hwnd ${NSD_AddStyle} $hwnd ${PBS_MARQUEE} ${NSD_CreateTimer} NSD_Timer.Callback 10 nsDialogs::Show FunctionEnd Function NSD_Timer.Callback ${NSD_KillTimer} NSD_Timer.Callback ; Kill the timer SendMessage $hwnd ${PBM_SETMARQUEE} 1 50 ; start=1|stop=0 interval(ms)=+N _again: MessageBox MB_YESNO "Stop the marquee?" IDNO _again SendMessage $hwnd ${PBM_SETMARQUEE} 0 0 FunctionEnd !insertmacro MUI_LANGUAGE "English"
Note that a Marquee Progress Bar always runs from left to right - you can't set it to any other position.
How to Create a Smooth Progress Bar control
A Smooth Progress Bar is one that is not cut up into small rectangles - i.e. the entire progress is one solid, smooth, bar.
Unfortunately, there are two caveats in this case:
1. The standard Progress Bar is styled by XP styles which override this style. For the same reason you can't have a Marquee progress bar _without_ XP Styles, you can't have a Smooth progress bar _with_ XP Styles (see also XPStyle).
2. The Smooth style (PBS_SMOOTH) can't be added -after- the control has been created by nsDialogs. So you have to create it with that style already set.
Below is an example that uses a Smooth Progress Bar, with XP Styles off.
!include "WinMessages.nsh" !include "MUI2.nsh" !include "nsDialogs.nsh" OutFile "test.exe" Section SectionEnd Var dialog Var hwnd Var null !define PB_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE} !define PBS_SMOOTH 0x01 !define /math PBM_SETRANGE32 ${WM_USER} + 6 Page Custom page.custom Function page.custom nsDialogs::Create 1018 Pop $dialog nsDialogs::CreateControl "msctls_progress32" \ ${DEFAULT_STYLES}|${PBS_SMOOTH} \ ${PB_EXSTYLE} \ 0 0 100% 10% \ "Test" \ Pop $hwnd ${NSD_CreateTimer} NSD_Timer.Callback 10 nsDialogs::Show FunctionEnd Function NSD_Timer.Callback ${NSD_KillTimer} NSD_Timer.Callback ; Kill the timer SendMessage $hwnd ${PBM_SETRANGE32} 0 100 SendMessage $hwnd ${PBM_SETPOS} 25 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 50 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 75 0 Sleep 2000 SendMessage $hwnd ${PBM_SETPOS} 100 0 FunctionEnd !insertmacro MUI_LANGUAGE "English" XPStyle off
How to let controls receive Hotkey (alt+letter) combinations
Only controls that have labels can be assigned a hotkey, simply by including an ampersand in its title. E.g.
${NSD_CreateCheckbox} 3% 3% 20% 8% "The hot&key here is alt+k"
However, when the page is first navigated to in NSIS, the NSIS dialog is what has focus, rather than the inner nsDialogs dialog. So set focus to the nsDialogs dialog before you tell nsDialogs to show it:
nsDialogs::Create 1018 Pop $dialog ; assuming you have a 'dialog' variable! ; further code here SendMessage $dialog ${WM_SETFOCUS} $HWNDPARENT 0 nsDialogs::Show
The NSIS dialog will still handle e.g. alt+N for the Next button as the hotkey event simply 'bubbles up' to the parent window if window with current focus does not react to it. ( Hint: That means you shouldn't set any hotkeys for the B(ack) or N(ext) letters! )
Using these methods, you can easily create an installer that can be navigated entirely and easily by keyboard-only.
How to create a sorted droplist control
Sometimes you may have to display a dropdown list with sorted information - for example, a list of folders or files (retrieved through one of the many filesearch scripts) that may not have come in sorted.
One solution would be to pre-sort the results using a sorting script or the Array plugin.
Another solution is to use a dropdown list which has a 'sorted' style, CBS_SORT, set on it so that its listings are automatically sorted.
Unfortunately this is not a style you can not add after the control has been created, so you have to create it yourself.
Below is a header file I wrote for use in our installer which lets us use the same syntax as nsDialogs uses for other controls.
/* nsDialogs_createDroplistSorted.nsh Header file for creating a sorted droplist control. Usage: ${NSD_CreateDroplistSorted} left top width height "" Creates the sorted droplist at the location specified. */ !ifndef NSDIALOGS_createDroplistSorted_INCLUDED !define NSDIALOGS_createDroplistSorted_INCLUDED !verbose push !verbose 3 !include WinMessages.nsh !define __NSD_DropListSorted_CLASS COMBOBOX !define __NSD_DropListSorted_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${WS_VSCROLL}|${WS_CLIPCHILDREN}|${CBS_AUTOHSCROLL}|${CBS_HASSTRINGS}|${CBS_DROPDOWNLIST}|${CBS_SORT} !define __NSD_DropListSorted_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE} !insertmacro __NSD_DefineControl DropListSorted !verbose pop !endif