NSIS: Custom page on StateChanged - installation

I have a some different license pages with check box on it. The Next button should be disabled if check box is unchecked. Is there an event that I can use if checkbox state changed? Here is my code of one of this
var Window
var labelDescription
var checkBoxIsUserAgree
Function CreateCustomLicense1
nsDialogs::Create 1018
Pop $Window
GetDlgItem $0 $HWNDPARENT
EnableWindow $0 0
${NSD_CreateLabel} 13u 22u 270u 96u "Description"
Pop $labelDescription
${NSD_CreateCheckBox} 10u 110u 100u 15u "I Agree"
$checkBoxIsUserAgree
FunctionEnd
Function ShowCustomLicence1
Call CreateCustomLicense1
nsDialogs::Show
Function
Function .oncheckBoxIsUserAgreeStateChanged ; what event I can use for track checkbox state changing
EnableWindow $0 1
FunctionEnd

The built-in NSIS license page supports a checkbox and can be used multiple times but if you insist on creating a custom page you just have to add a on* handler:
!include nsDialogs.nsh
Var checkBoxIsUserAgree
Function ShowCustomLicence1
nsDialogs::Create 1018
Pop $1
GetDlgItem $0 $HWNDPARENT 1
EnableWindow $0 0
${NSD_CreateLabel} 13u 22u 270u 90u "Description"
Pop $1
${NSD_CreateCheckBox} 10u 110u 100u 15u "I Agree"
Pop $checkBoxIsUserAgree
${NSD_OnClick} $checkBoxIsUserAgree oncheckBoxIsUserAgreeStateChanged1
nsDialogs::Show
FunctionEnd
Function oncheckBoxIsUserAgreeStateChanged1
Pop $1 ; Throw away parameter
${NSD_GetState} $checkBoxIsUserAgree $1
EnableWindow $0 $1
FunctionEnd
Page Custom ShowCustomLicence1
Page InstFiles

Related

With in Graphical Installer & NSIS, the text of Label overlapped when I changed it dynamically

I created a custom page which contains a label and two buttons to control the label's contents.
I suppose to set the text of the label within callbacks of the buttons, as the following codes:
Function FuncShowNewFeature
; ...
; Add Controls
${NSD_CreateLabel} 0 13u 100% 12u "Show new features here"
Pop $lblContents
${GraphicalInstallerRedrawLabel} $lblContents
${NSD_CreateButton} 0 -13u 40u 13u "Prev"
Pop $btnPrev
${NSD_OnClick} $btnPrev PrevFeature ; callback
${NSD_CreateButton} -40u -13u 40u 13u "Next"
Pop $btnNext
${NSD_OnClick} $btnNext NextFeature ; callback
# Put this macro before EACH calling nsDialogs::Show to draw background properly
${GraphicalInstallerRedrawnsDialogsPage}
nsDialogs::Show
FunctionEnd
Function NextFeature
${NSD_SetText} $lblContents "To show the next tip of new-feature"
${GraphicalInstallerRedrawLabel} $lblContents ;I don't know whether this macro is necessary here
FunctionEnd
Function PrevFeature
${NSD_SetText} $lblContents "To show the previous tip of new-feature"
${GraphicalInstallerRedrawLabel} $lblContents ;I don't know whether this macro is necessary here
FunctionEnd
But the result shows something wrong, which the "new" text overlapped on the old ones, just like the label has not been refreshed/cleared before redrawing.
Did I miss any necessary calling in my process?
You are missing GraphicalInstaller::SubclassLabel /NOUNLOAD $variable_name
The correct code:
Function FuncShowNewFeature
; ...
; Add Controls
${NSD_CreateLabel} 0 13u 100% 12u "Show new features here"
Pop $lblContents
${GraphicalInstallerRedrawLabel} $lblContents
GraphicalInstaller::SubclassLabel /NOUNLOAD $lblContents # <<< ADDED HERE
${NSD_CreateButton} 0 -13u 40u 13u "Prev"
Pop $btnPrev
${NSD_OnClick} $btnPrev PrevFeature ; callback
${NSD_CreateButton} -40u -13u 40u 13u "Next"
Pop $btnNext
${NSD_OnClick} $btnNext NextFeature ; callback
# Put this macro before EACH calling nsDialogs::Show to draw background properly
${GraphicalInstallerRedrawnsDialogsPage}
nsDialogs::Show
FunctionEnd
Function NextFeature
${NSD_SetText} $lblContents "To show the next tip of new-feature"
FunctionEnd
Function PrevFeature
${NSD_SetText} $lblContents "To show the previous tip of new-feature"
FunctionEnd
GraphicalInstaller::Subclass[CONTROL] is part of
${GraphicalInstallerRedraw[CONTROL]} macro.
This works fine for [CONTROL] of type RadioButton or CheckBox, but it is missing in Label.
We will fix this in next release, sorry for this inconsistency.
One simple workaround is to just hide the label while you update its text:
!include nsDialogs.nsh
Page Custom gfxpage
Function onClick
Pop $0
System::Call 'kernel32::GetTickCount()i.r0' ; "Arbitrary" number
ShowWindow $2 0
${NSD_SetText} $2 "$0$0$0"
ShowWindow $2 1
FunctionEnd
Function .onInit
InitPluginsDir
File /oname=$PLUGINSDIR\image.bmp "${NSISDIR}\Contrib\Graphics\Header\nsis-r.bmp"
FunctionEnd
Function gfxpage
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 -13u 100% 12u "Click me"
Pop $1
${NSD_OnClick} $1 onClick
${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!"
Pop $2
SetCtlColors $2 000000 transparent
${NSD_CreateBitmap} 0 0 100% 12u ""
Pop $3
${NSD_SetBitmap} $3 $PLUGINSDIR\image.bmp $4
nsDialogs::Show
${NSD_FreeBitmap} $4
FunctionEnd

NSIS optional custom pages

I want to create a checkbox in NSIS at the end of the installation process, when checked, it will lead the user to a custom page that has a bunch of radioboxes that lead the user to another custom page (depending on the choice) and so on.
I know how to create a custom page using nsDialogs, but I can't figure out the logic behind multiple optional custom pages. Any help is appreciated.
Alternatively, is there a way to create multiple checkbox/radiobox groups that are disabled by default (except the first one) and only activated when the user selects a box in a group before it?
Pages are skipped by calling Abort in the page Pre-callback. Then all you have to do is keep track of which page you want to show and which you want to skip:
!include nsDialogs.nsh
!include LogicLib.nsh
Section "Do custom page thing" SID_DOCUSTOMPAGES
SectionEnd
Page Components
Page InstFiles
Page Custom Cust1Pre Cust2Next
Page Custom CustAPre
Page Custom CustBPre
Var WantedPage
Function Cust1Pre
${IfNot} ${SectionIsSelected} ${SID_DOCUSTOMPAGES}
StrCpy $WantedPage ""
Abort
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateRadioButton} 0 30u 100% 10u "Page A"
Pop $1
${NSD_Check} $1
${NSD_CreateRadioButton} 0 40u 100% 10u "Page B"
Pop $2
nsDialogs::Show
FunctionEnd
Function Cust2Next
${NSD_GetState} $1 $0
${If} $0 <> ${BST_UNCHECKED}
StrCpy $WantedPage A
${Else}
StrCpy $WantedPage B
${EndIf}
FunctionEnd
Function CustAPre
${IfNotThen} $WantedPage == A ${|} Abort ${|}
GetDlgItem $0 $hWndParent 1
SendMessage $0 ${WM_SETTEXT} "" "STR:$(^CloseBtn)" ; Change button text since page B is skipped and we are now the last page
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 30u 100% 10u "Page A"
Pop $0
nsDialogs::Show
FunctionEnd
Function CustBPre
${IfNotThen} $WantedPage == B ${|} Abort ${|}
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 30u 100% 10u "Page B"
Pop $0
nsDialogs::Show
FunctionEnd
You can get rid of the WM_SETTEXT workaround by having a single page that is "A" or "B":
!include nsDialogs.nsh
!include LogicLib.nsh
Section "Do custom page thing" SID_DOCUSTOMPAGES
SectionEnd
Page Components
Page InstFiles
Page Custom Cust1Pre Cust2Next
Page Custom CustAOrBPre
Var WantedPage
Function Cust1Pre
${IfNot} ${SectionIsSelected} ${SID_DOCUSTOMPAGES}
StrCpy $WantedPage ""
Abort
${EndIf}
nsDialogs::Create 1018
Pop $0
${NSD_CreateRadioButton} 0 30u 100% 10u "Page A"
Pop $1
${NSD_Check} $1
${NSD_CreateRadioButton} 0 40u 100% 10u "Page B"
Pop $2
nsDialogs::Show
FunctionEnd
Function Cust2Next
${NSD_GetState} $1 $0
${If} $0 <> ${BST_UNCHECKED}
StrCpy $WantedPage A
${Else}
StrCpy $WantedPage B
${EndIf}
FunctionEnd
Function CustAPre
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 30u 100% 10u "Page A"
Pop $0
nsDialogs::Show
FunctionEnd
Function CustBPre
nsDialogs::Create 1018
Pop $0
${NSD_CreateButton} 0 30u 100% 10u "Page B"
Pop $0
nsDialogs::Show
FunctionEnd
Function CustAOrBPre
${If} $WantedPage == A
Call CustAPre
${Else}
Call CustBPre
${EndIf}
FunctionEnd
Having just a single page with disabled options is of course better:
!include nsDialogs.nsh
!include LogicLib.nsh
Page InstFiles
Page Custom CustPre
Function CustPre
nsDialogs::Create 1018
Pop $0
${NSD_CreateCheckBox} 10 30u 100% 10u "Enable other stuff"
Pop $0
${NSD_OnClick} $0 OnCheckChange
${NSD_CreateRadioButton} 10 50u 100% 10u "Foo"
Pop $1
${NSD_AddStyle} $1 ${WS_GROUP}
${NSD_Check} $1
${NSD_CreateRadioButton} 10 70u 100% 10u "Bar"
Pop $2
${NSD_RemoveStyle} $2 ${WS_TABSTOP}
Push $0
Call OnCheckChange ; Enforce state
nsDialogs::Show
FunctionEnd
!macro SetRadiosEnabled state
EnableWindow $1 ${state}
EnableWindow $2 ${state}
!macroend
Function OnCheckChange
Pop $0
${NSD_GetState} $0 $0
${If} $0 <> ${BST_UNCHECKED}
!insertmacro SetRadiosEnabled 1
${Else}
!insertmacro SetRadiosEnabled 0
${EndIf}
FunctionEnd

Cant understand why ${NSD_GetState} $Checkbox is not working

Can anyone explain to me, why ${NSD_GetState} $Checkbox is not working ?
I lost about 4 hours trying to find out what is wrong. I tried diffrent variants but in THIS script they are not working.
Actualy it is my first attempt to make a nsis installer, so I even dont know where should I look for mistake or I just dont understand the logic of this language.
From Russia with love :)
And sorry for my bad english
!define NAME "Simple LiveUSB installer"
!define FILENAME "USB"
!define VERSION "v0.1"
Name "${NAME} ${VERSION}"
OutFile "${FILENAME}.exe"
SetCompressor LZMA
ShowInstDetails hide
XPStyle on
!include MUI2.nsh
!include FileFunc.nsh
!include nsDialogs.nsh
;!include LogicLib.nsh
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\HEADER2.bmp"
!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\media-floppy.ico"
Page custom drivePage
Page custom Var123
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "Russian"
LangString DrivePage_Title ${LANG_RUSSIAN} "TEXT"
LangString DrivePage_Title2 ${LANG_RUSSIAN} "TEXT"
LangString DrivePage_Text ${LANG_RUSSIAN} "TEXT"
LangString DrivePage_Text2 ${LANG_RUSSIAN} "Format"
LangString DrivePage_Input ${LANG_RUSSIAN} "Choose"
Var Label
Var Label2
Var Checkbox
;Var Checkbox_State
Var DestDriveHW
Var DestDrive
# Functions #######################################
Function drivePage
!insertmacro MUI_HEADER_TEXT $(DrivePage_Title) $(DrivePage_Title2)
nsDialogs::Create 1018
${If} $DestDrive == ""
GetDlgItem $6 $HWNDPARENT 1
EnableWindow $6 0
${EndIf}
${NSD_CreateLabel} 0 0 100% 160 $(DrivePage_Text)
Pop $Label
${NSD_CreateLabel} 10 182 100% 15 $(DrivePage_Input)
Pop $Label2
${NSD_CreateDroplist} 10 200 13% 20 ""
Pop $DestDriveHw
${NSD_OnChange} $DestDriveHw db_select.onchange
${GetDrives} "FDD" driveListFiller
${If} $DestDrive != ""
${NSD_CB_SelectString} $DestDriveHw $DestDrive
${EndIf}
${NSD_CreateCheckbox} 80 203 100% 10u $(DrivePage_Text2)
Pop $Checkbox
${If} $Checkbox_State == ${BST_CHECKED}
${NSD_Check} $Checkbox_State
${EndIf}
nsDialogs::Show
FunctionEnd
Function db_select.onchange
Pop $DestDriveHw
${NSD_GetText} $DestDriveHw $0
StrCpy $DestDrive "$0"
GetDlgItem $6 $HWNDPARENT 1
EnableWindow $6 1
FunctionEnd
Function driveListFiller
SendMessage $DestDriveHw ${CB_ADDSTRING} 0 "STR:$9"
Push 1
FunctionEnd
Function Var123
Pop $Checkbox
MessageBox mb_ok "FIN Checkbox_State=$Checkbox_State Checkbox=$Checkbox"
${NSD_GetState} $Checkbox $0
${If} $0 <> 0
MessageBox mb_ok "Custom checkbox was checked... N=$0"
${EndIf}
${If} $0 == 0
MessageBox mb_ok "Custom checkbox ZERO... N=$0"
${EndIf}
Functionend
# Section #######################################
Section "" main
InitPluginsDir
File /oname=$PLUGINSDIR\syslinux.cfg "${NSISDIR}\plugins\syslinux.cfg"
File /oname=$PLUGINSDIR\syslinux.exe "${NSISDIR}\plugins\syslinux.exe"
File /oname=$PLUGINSDIR\nsExec.dll "${NSISDIR}\plugins\nsExec.dll"
StrCpy $R0 $DestDrive -1
;ExpandEnvStrings $0 %COMSPEC%
;nsExec::Exec '"$0" /c echo. | format $R0 /q /x /v:LiveUSB /fs:fat32'
nsExec::Exec '$PLUGINSDIR\syslinux.exe -maf -d boot\syslinux $R0'
;SendMessage $Checkbox ${BM_GETSTATE} 0 0 $0
;${If} $0 != 0
; MessageBox MB_OK checked!
;${EndIf}
;Pop $Checkbox
;MessageBox mb_ok "FIN Checkbox_State=$Checkbox_State Checkbox=$Checkbox"
;${NSD_GetState} $Checkbox $0
;${If} $0 <> 0
; MessageBox mb_ok "Custom checkbox was checked... N=$0"
;${EndIf}
CopyFiles $PLUGINSDIR\syslinux.cfg "$R0\syslinux.cfg"
SectionEnd
There is so much unrelated code in your example that it is a bit hard to understand what you really want to do.
If you want to retrieve the state of a checkbox on another page then you must save the state because the checkbox control is destroyed when you leave the page.
!include nsDialogs.nsh
Var hwndCheckbox
Var CheckboxState
Page Custom myPageWithCombobox myPageWithComboboxLeaveCallback
Page Custom myPageWithComboState
Function .onInit
StrCpy $CheckboxState ${BST_CHECKED} ; Set the initial state. This is optional but useful if you use $CheckboxState in a section when the installer is silent
FunctionEnd
Function myPageWithCombobox
nsDialogs::Create 1018
Pop $0
${NSD_CreateCheckbox} 80 203 100% 10u $(DrivePage_Text2)
Pop $hwndCheckbox
${NSD_SetState} $hwndCheckbox $CheckboxState ; Reuse the existing state so it is correct when the back button is used
nsDialogs::Show
FunctionEnd
Function myPageWithComboboxLeaveCallback
${NSD_GetState} $hwndCheckbox $CheckboxState ; Save the state so we can retrieve it on the next page
FunctionEnd
Function myPageWithComboState
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 160 CheckboxState=$CheckboxState
Pop $0
nsDialogs::Show
FunctionEnd

How to change custom page label text on the fly in nsis?

I have written a custom page where i want to change the label text on the fly .I tried following code but some how I could not bale to change the text .
Function Maintainance
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 12u "The $CurrentVersion complete installation folder is available at the below link"
Pop $Label
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $1 $0 1006
SendMessage $1 ${WM_SETTEXT} 0 "STR:new value 111111"
nsDialogs::Show
FunctionEnd
Any pointer on this will be a help.
The custom page is not visible until you call nsDialogs::Show. Any dynamic action has to happen after that with a timer or in response to a user action:
Page Custom MyPageCreate
Page InstFiles
!include nsDialogs.nsh
var mylabel
Function MyPageCreate
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 0 100% 12u "Hello"
Pop $mylabel
${NSD_CreateButton} 0 50% 50% 12u "Change"
Pop $0
${NSD_OnClick} $0 ChangeIt
nsDialogs::Show
FunctionEnd
Function ChangeIt
System::Call kernel32::GetTickCount()i.r0
SendMessage $mylabel ${WM_SETTEXT} 0 "STR:World! $0"
FunctionEnd

using nsis installer, adding custom radiobuttons, calling sections according to radiobutton chosen

I want that if none of the RadioButtons are selected , then ,when the Next button is pressed, then it should give an alert that PLEASE CHOSE ATLEAST ONE ITEM, and it should not go to the next Dialog.
Also, I want that if the user selects the option : UPDATE EXISTING SOFTWARE, then only some files are copied, and if the other radiobutton is selected , then all files are copied,
Is this possible using sections or functions have to be used? can i call a Section, like if RadioButton 1 is chosen, then SECTION CREATEALLFILES is called, else SECTION CREATEONLYTWOFILES is called?
According to me, i think i want the code to HOW TO HOLD THE ids of these two RadioButtons and use them accordingly , to call different sections or functions. What would be the code? Please help?
Also, after pressing NEXT on this page, the next dialog will come as in image below: i want to show a LABEL , whether DEMO is done, or UPDATE is running, for this i will add a Label using Resource Hacker, but how to display that Label and hide it according to user choice of RadioButton
You can select/unselect sections or just put the logic in a single section, this example does both:
!include nsDialogs.nsh
!include Sections.nsh
var InstallType
Section
#Install common files...
${If} $InstallType == DEMO
#Do demo specific stuff
${Else}
#Do update specific stuff
${EndIf}
SectionEnd
Section "" SEC_DEMO
#Install demo..
SectionEnd
Section "" SEC_UPDATE
#Do update..
SectionEnd
Page custom InstTypePageCreate InstTypePageLeave
Function InstTypePageCreate
nsDialogs::Create 1018
pop $0
${NSD_CreateRadioButton} 0 50u 100% 10u "Demo"
pop $1
${IfThen} $InstallType == DEMO ${|} ${NSD_Check} $1 ${|}
${NSD_CreateRadioButton} 0 70u 100% 10u "Update"
pop $2
${IfThen} $InstallType == UPDATE ${|} ${NSD_Check} $2 ${|}
nsDialogs::Show
FunctionEnd
Function InstTypePageLeave
${NSD_GetState} $1 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType DEMO
!insertmacro UnselectSection ${SEC_UPDATE}
!insertmacro SelectSection ${SEC_DEMO}
${Else}
${NSD_GetState} $2 $0
${If} $0 = ${BST_CHECKED}
StrCpy $InstallType UPDATE
!insertmacro UnselectSection ${SEC_DEMO}
!insertmacro SelectSection ${SEC_UPDATE}
${Else}
MessageBox MB_ICONSTOP "You must select something!"
Abort
${EndIf}
${EndIf}
FunctionEnd
To set the text on the next page, just use ${NSD_SetText} $hwndYourLabel "Text" and ShowWindow inside a if block that tests $InstallType (This code needs to be in the show function callback (MUI_PAGE_CUSTOMFUNCTION_SHOW) for that page)

Resources