I was originally going to ask how to do several of the features I how have working in the set file. so I have 2 questions now. Patting myself on the back since I figured out everything else:)
Ok so here is what I would like:
Is it possible to have the list taller so no scrolling? also
Can we have the title be just that and no checkbox? (They are radio-buttons and the title is the grouping of them)
How could I go about creating the same thing just in a custom page so I have control over the elements? (including the mouse move over feature of components page)
Thanks for looking and hope you can help me code it out.
Code: (And yes I know the !included's are not all needed in the test buy my app does so I just left it) Also the verification and a few other settings are not finished, I was just getting some examples to work.)
!include WinVer.nsh
!include LogicLib.nsh
!include x64.nsh
!include FileFunc.nsh
!include MUI.nsh
!include WinMessages.nsh
!include InstallOptions.nsh
!include Sections.nsh
!define MUI_COMPONENTSPAGE_TEXT_TOP "Please select the options that best match your setup and preferances."
!define MUI_COMPONENTSPAGE_TEXT_COMPLIST " "
!define MUI_PAGE_HEADER_TEXT "Setup Options"
!define MUI_PAGE_HEADER_SUBTEXT " "
!define MUI_COMPONENTSPAGE_smallDESC
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "English"
SectionGroup /e "!Sets" SetsTitle #Section Should be Radio Buttons
Section "Set 1" Set1
SectionEnd
Section /o "Set 2" Set2
SectionEnd
Section /o "Skip" SetSkip
SectionEnd
SectionGroupEnd
SubSection /e "!Setup" SetupTitle #Section Should be Radio Buttons
Section "Setup 1" setup1
SectionEnd
Section /o "Setup 2" setup2
SectionEnd
Section /o "None" setupNone
SectionEnd
SubSectionEnd
SubSection /e "!AutoLoad" ALTitle #Section Should be Radio Buttons
Section "Yes" ALYes
SectionEnd
Section /o "No" ALNo
SectionEnd
SubSectionEnd
SubSection /e "!Disable Feature" DFTitle #Section Should be Check Boxes
Section "Feature 1" DAF1
SectionEnd
Section "Feature 2" DAF2
SectionEnd
SubSectionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SetsTitle} "Sets Description"
!insertmacro MUI_DESCRIPTION_TEXT ${Set1} "Set1 Description"
!insertmacro MUI_DESCRIPTION_TEXT ${Set2} "Set2 Description"
!insertmacro MUI_DESCRIPTION_TEXT ${SetSkip} "SetNone Description"
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section -InstallSelectedOptions
${If} ${SectionIsSelected} ${set1}
MessageBox MB_OK|MB_USERICON|MB_TOPMOST "set1"
${endif}
${If} ${SectionIsSelected} ${set2}
MessageBox MB_OK|MB_USERICON|MB_TOPMOST "set2"
${endif}
${If} ${SectionIsSelected} ${setskip}
MessageBox MB_OK|MB_USERICON|MB_TOPMOST "setnone"
${endif}
${If} ${Setup1} == true
${endif}
SectionEnd
Function .onInit
StrCpy $1 ${set1} ; Group 1 - Option 1 is selected by default
StrCpy $2 ${setup1} ; Group 2 - Option 1 is selected by default
FunctionEnd
Function .onSelChange
!insertmacro StartRadioButtons $1
!insertmacro RadioButton ${set1}
!insertmacro RadioButton ${set2}
!insertmacro RadioButton ${setskip}
!insertmacro EndRadioButtons
!insertmacro StartRadioButtons $2
!insertmacro RadioButton ${setup1}
!insertmacro RadioButton ${setup2}
!insertmacro RadioButton ${setupNone}
!insertmacro EndRadioButtons
FunctionEnd
You cannot combine radio buttons and checkmarks on the built-in components page but you can use your own custom radio button .BMP file with !define MUI_COMPONENTSPAGE_CHECKBITMAP "myradio.bmp".
You can customize the MUI components page a little bit by defining MUI_COMPONENTSPAGE_SMALLDESC or MUI_COMPONENTSPAGE_NODESC but if you need more than that you have to copy and modify "...\NSIS\Contrib\UIs\modern.exe" with Resource Hacker and apply this custom UI with MUI_UI.
Replicating the components page as a custom page might be possible but it is a lot of work. nsDialogs does not have much support for the TreeView control so you are pretty much on your own if you go down this route.
Related
I wanted to set the by default Focus to the "License Agreement" checkbox in the License Agreement Page using NSIS. And then the taborder should work.
Please help me how to set the focus?
Below is my code snippet:
!include LogicLib.nsh
!define MUI_TEXT_WELCOME_INFO_TITLE $(welcometitle)
!define MUI_TEXT_WELCOME_INFO_TEXT $(welcometext)
!insertmacro MUI_PAGE_WELCOME
!define MUI_LICENSEPAGE_CHECKBOX ""
!define MUI_INNERTEXT_LICENSE_BOTTOM ""
!define MUI_INNERTEXT_LICENSE_TOP ""
!define MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX ""
!define MUI_TEXT_LICENSE_TITLE $(licensetitle)
!define MUI_TEXT_LICENSE_SUBTITLE $(licensesubtitle)
!define MUI_LICENSEPAGE_CHECKBOX_TEXT $(licensecheckboxtext)
!insertmacro MUI_PAGE_LICENSE "C:\Program Files (x86)\NSIS\Docs\Modern UI 2\license.txt"
!define MUI_DIRECTORYPAGE_TEXT_TOP $(mydirtoptext)
!define MUI_TEXT_DIRECTORY_TITLE $(mydirtitle)
!define MUI_TEXT_DIRECTORY_SUBTITLE $(mydirsubtitle)
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_TEXT_FINISH_INFO_TITLE $(Finishpagetitle)
!define MUI_TEXT_FINISH_INFO_TEXT $(Finishpagesubtitle)
!define MUI_FINISHPAGE_RUN ""
!define MUI_FINISHPAGE_RUN_TEXT $(FinishonlineReg)
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
!insertmacro MUI_LANGUAGE "English"
; The stuff to install
Section "My TestApp (required)"
SectionEnd
The Windows UI guidelines says:
For keyboard navigation, tab order should flow in a logical order, generally from left to right, top to bottom.
but if you think you must force then you can do this:
!include WinMessages.nsh
!include MUI2.nsh
!insertmacro MUI_PAGE_WELCOME
!define MUI_LICENSEPAGE_CHECKBOX ""
!define MUI_PAGE_CUSTOMFUNCTION_SHOW myForceLicenseFocus
!insertmacro MUI_PAGE_LICENSE "${__FILE__}"
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE English
Function myForceLicenseFocus
!if ${MUI_SYSVERSION} >= 2.0
FindWindow $0 "BUTTON" "" $mui.LicensePage
!else
FindWindow $0 "#32770" "" $hWndParent
FindWindow $0 "BUTTON" "" $0
!endif
System::Call 'USER32::SetFocus(pr0)'
!define /ifndef WM_CHANGEUISTATE 0x127
System::Call 'USER32::PostMessage(pr0,i${WM_CHANGEUISTATE},p0x30002,p0)' ; This forces the checkbox to display the focus rectangle
System::Call 'USER32::SetWindowPos(pr0,p0,i,i,i,i,i0x13)' ; Change tab order
FunctionEnd
I have managed to customize the message shown in the title / subtitle after installation:
!define APP_NAME 'Test15'
name ${APP_NAME}
outfile '${APP_NAME}.exe'
showinstdetails show
InstallDir '$PROGRAMFILES\${APP_NAME}'
!include 'mui.nsh'
Var CompletedText
CompletedText $CompletedText
Var MUI_HeaderText
Var MUI_HeaderSubText
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "$MUI_HeaderText"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "$MUI_HeaderSubText"
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "One"
MessageBox MB_OK "Section One"
SectionEnd
Section -"Post"
;MessageBox MB_OK "Section Post"
StrCpy $CompletedText "My custom text"
StrCpy $MUI_HeaderText "My custom header text"
StrCpy $MUI_HeaderSubText "My custom header subText"
;MessageBox MB_OK "OUTING Section Post"
SectionEnd
My problem is that when I need to add a second part installation (it is a new mandatory requirement), and then not get modify / customize messages title / subtitle shown at the end:
!define APP_NAME 'Test15'
name ${APP_NAME}
outfile '${APP_NAME}.exe'
showinstdetails show
InstallDir '$PROGRAMFILES\${APP_NAME}'
!include 'mui.nsh'
Var CompletedText
CompletedText $CompletedText
Var MUI_HeaderText
Var MUI_HeaderSubText
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "$MUI_HeaderText"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "$MUI_HeaderSubText"
!insertmacro MUI_PAGE_INSTFILES
;This my second part instalation!!
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "One"
MessageBox MB_OK "Section One"
SectionEnd
Section -"Post"
;MessageBox MB_OK "Section Post"
StrCpy $CompletedText "My custom text"
StrCpy $MUI_HeaderText "My custom header text"
StrCpy $MUI_HeaderSubText "My custom header subText"
;MessageBox MB_OK "OUTING Section Post"
SectionEnd
Now, the same message is always displayed at the end for Title/Subtitle: "Installation Complete" // "Setup was completed successfully.". Nevertheless, the 'completed' text value is modified successfully ("My custom text").
Please, can anyone help me?
Thanks in advance!
If you read the MUI documentation carefully you will find this in the "Page settings" section:
Page settings apply to a single page and should be set before inserting a page macro. The same settings can be used for installer and uninstaller pages. You have to repeat the setting if you want it to apply to multiple pages.
Only the defines listed under "Interface settings" are global.
!include MUI.nsh
!define MUI_PAGE_HEADER_TEXT "Install page #1"
!define MUI_PAGE_HEADER_SUBTEXT "Foo foo foo"
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Did part 1"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "..."
!insertmacro MUI_PAGE_INSTFILES
!define MUI_PAGE_HEADER_TEXT "Install page #2"
!define MUI_PAGE_HEADER_SUBTEXT "Bar bar bar!"
!define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "All done"
!define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "ZZZzzz.."
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
I have an installer using the Modern UI 2 (MUI 2) that installs up to three components into different locations.
I use a MUI_PAGE_COMPONENTS page and multiple MUI_PAGE_DIRECTORY pages which are skipped automatically if the corresponding section is not selected (like described here).
So far so good.
However, if the last of the three components is not chosen to be installed, the button on the previous (not-skipped) directory page should say Install instead of Next, because next the last directory page will be skipped and the installation will be executed.
Since we already know which page will be skipped after we leave the components page, I wonder if there is a way to make it work?
Minimal example:
!include MUI2.nsh
InstallDir $EXEDIR
OutFile "skip.exe"
RequestExecutionLevel user
ShowInstDetails show
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_PAGE_CUSTOMFUNCTION_PRE directoryPreA
!insertmacro MUI_PAGE_DIRECTORY
!define MUI_PAGE_CUSTOMFUNCTION_PRE directoryPreB
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "A" SEC_A
DetailPrint "Installing A..."
SectionEnd
Section /o "B" SEC_B
DetailPrint "Installing B..."
SectionEnd
Function directoryPreA
# Skips the directory page for A if not chosen for installation.
${Unless} ${SectionIsSelected} ${SEC_A}
Abort
${EndUnless}
FunctionEnd
Function directoryPreB
# Skips the directory page for B if not chosen for installation.
${Unless} ${SectionIsSelected} ${SEC_B}
Abort
${EndUnless}
FunctionEnd
!include MUI2.nsh
!insertmacro MUI_PAGE_COMPONENTS
!define MUI_DIRECTORYPAGE_TEXT_TOP "Dir:A"
!define MUI_PAGE_CUSTOMFUNCTION_PRE directoryPreA
!insertmacro MUI_PAGE_DIRECTORY
!define MUI_DIRECTORYPAGE_TEXT_TOP "Dir:B"
!define MUI_PAGE_CUSTOMFUNCTION_PRE directoryPreB
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "A" SEC_A
DetailPrint "Installing A..."
SectionEnd
Section /o "B" SEC_B
DetailPrint "Installing B..."
SectionEnd
Function .onSelChange
GetDlgItem $0 $HWNDPARENT 1
${If} ${SectionIsSelected} ${SEC_A}
${OrIf} ${SectionIsSelected} ${SEC_B}
SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^NextBtn)"
${Else}
SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^InstallBtn)"
${EndIf}
FunctionEnd
Function directoryPreA
# Skips the directory page for A if not chosen for installation.
${IfNot} ${SectionIsSelected} ${SEC_A}
Abort
${ElseIfNot} ${SectionIsSelected} ${SEC_B}
GetDlgItem $0 $HWNDPARENT 1
SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^InstallBtn)"
${EndIf}
FunctionEnd
Function directoryPreB
# Skips the directory page for B if not chosen for installation.
${Unless} ${SectionIsSelected} ${SEC_B}
Abort
${EndUnless}
FunctionEnd
I want to make a section inside of a sectiongroup required for that section group but not required for the entire install if the group is unchecked. I've tried "SectionIn R0" but this makes that section required for the entire install and I only want it to be required if they select the group itself.
SectionGroup "group"
Section "required for section group"
SectionIn RO
SectionEnd
Section "optional"
SectionEnd
SectionGroupEnd
You can't do this with just properties, you need some actual code:
!include Sections.nsh
!include LogicLib.nsh
SectionGroup /e "group"
Section "required for section group" SEC_REQ
SectionIn RO
SectionEnd
Section "optional" SEC_OPT
SectionEnd
SectionGroupEnd
Function .onSelChange
${If} ${SectionIsSelected} ${SEC_OPT}
!define /math MYSECTIONFLAGS ${SF_SELECTED} | ${SF_RO}
!insertmacro SetSectionFlag ${SEC_REQ} ${MYSECTIONFLAGS}
!undef MYSECTIONFLAGS
${Else}
!insertmacro ClearSectionFlag ${SEC_REQ} ${SF_RO}
${EndIf}
FunctionEnd
Note that there is a "bug" when unchecking the section group itself, to workaround that, you need to keep some global state since nsis does not tell you which section generated the notification. The following code has better logic:
!include Sections.nsh
!include LogicLib.nsh
SectionGroup /e "group" SEC_GRP
Section "required for section group" SEC_REQ
SectionIn RO
SectionEnd
Section "optional" SEC_OPT
SectionEnd
Section "" PRIVSEC_TOGGLESTATE ;hidden section to keep track of state
SectionEnd
SectionGroupEnd
Function .onSelChange
!define /math SECFLAGS_SELRO ${SF_SELECTED} | ${SF_RO}
${IfNot} ${SectionIsSelected} ${PRIVSEC_TOGGLESTATE}
${AndIf} ${SectionIsReadOnly} ${SEC_REQ}
!insertmacro ClearSectionFlag ${SEC_REQ} ${SECFLAGS_SELRO}
${EndIf}
${If} ${SectionIsSelected} ${SEC_OPT}
!insertmacro SetSectionFlag ${SEC_REQ} ${SECFLAGS_SELRO}
${Else}
!insertmacro ClearSectionFlag ${SEC_REQ} ${SF_RO}
${EndIf}
${If} ${SectionIsSelected} ${SEC_REQ}
!insertmacro SelectSection ${PRIVSEC_TOGGLESTATE}
${Else}
!insertmacro UnselectSection ${PRIVSEC_TOGGLESTATE}
${EndIf}
!undef SECFLAGS_SELRO
FunctionEnd
You can also set the sections as mandatory sections by using the SectionSetFlags command. You simply need to add it to the .onInit function as follows:
SectionGroup "group" Sec01
Section "required for section group"
SectionIn RO
SectionEnd
Section "optional" Sec02
SectionEnd
SectionGroupEnd
Function .onInit
SectionSetFlags ${Sec01} 17
FunctionEnd
This will gray "group" out, but it will be selected and installed as expected.
You can also setup a custom function which is being called when user clicks "Next" but no option is selected. In this function, you can check if any of Sections is selected or, as I did, check the variable which is set to "nothingSelected" on init, then modified when any section is created. If you put "Abort" in the custom function, the installer will stay on the same page. Here is a snippet:
page license
page directory
page components "" "" testSelection
page instfiles
function .onInit
StrCpy $somethingSelected "nothingSelected"
functionEnd
function testSelection
${If} $somethingSelected == "nothingSelected"
MessageBox MB_OK "Please select any option"
Abort
${EndIf}
functionEnd
function .onSelChange
#selecting mutually exclusive sections (removed for clarity)
StrCpy $somethingSelected $1
functionEnd
I want to conditionally set the first Installation type in Component page based on checking if some files already exists on the machine.
I've already tried two different approachs. 1) using SetCurInstType, 2) conditionally defining the InstType sequence order on the basis of a "file exist" check.
Both the approaches have been tested using an UDF function. This UDF function has been used, alternatively, as input for the MUI_PAGE_CUSTOMFUNCTION_LEAVE of MUI_PAGE_LICENSE and for the MUI_PAGE_CUSTOMFUNCTION_PRE of MUI_PAGE_COMPONENTS.
Both tests didn't work as expected
Approach 1)
InstType "Install (all)"
InstType "Install (minimal)"
!define USER_ALL_INST_TYPE 1
!define USER_MIN_INST_TYPE 2
!define MUI_PAGE_CUSTOMFUNCTION_PRE SetInitInstType
!insertmacro MUI_PAGE_COMPONENTS
Section "1" Sec1
SectionIn ${USER_ALL_INST_TYPE} ${USER_MIN_INST_TYPE}
... other code
SectionEnd
Section "2" Sec2
SectionIn ${USER_ALL_INST_TYPE}
... other code
SectionEnd
Function SetInitInstType
IfFileExists "<file_path>" 0 endSetInitInstType
SetCurInstType ${USER_MIN_INST_TYPE}
endSetInitInstType:
FunctionEnd
Approach 2)
!define MUI_PAGE_CUSTOMFUNCTION_PRE SetInitInstType
!insertmacro MUI_PAGE_COMPONENTS
Section "1" Sec1
SectionIn ${USER_ALL_INST_TYPE} ${USER_MIN_INST_TYPE}
... other code
SectionEnd
Section "2" Sec2
SectionIn ${USER_ALL_INST_TYPE}
... other code
SectionEnd
Function SetInitInstType
IfFileExists "<file_path>" 0 SetAllInstType
InstType "Install (minimal)"
InstType "Install (all)"
!define USER_MIN_INST_TYPE 1
!define USER_ALL_INST_TYPE 2
Goto endSetInitInstType
SetAllInstType:
InstType "Install (all)"
InstType "Install (minimal)"
!define USER_ALL_INST_TYPE 1
!define USER_MIN_INST_TYPE 2
endSetInitInstType:
FunctionEnd
After Condition check, if file existed, the expected result would be that the Install Mode ComboBox in Component page was initialized with the "Install (minimal)" option
The actual result is instead as follow:
Approach 1) --> All sections are disabled and the Install Mode ComboBox is initialized with the "Custom" option
Approach 2) --> I receive an error during script compiling
Section: "1" ->(Sec1)
SectionIn: Usage: SectionIn InstTypeIdx [InstTypeIdx [...]]
Error in script "<script_name>.nsi" on line XXX -- aborting creation process
Any suggestion would be really appreciated
Don't ask me why but SectionIn uses a different index system than all the other inst type functions.
Unlike SectionIn the index is zero based, which means the first install type's index is 0
!include MUI2.nsh
!define MUI_PAGE_CUSTOMFUNCTION_PRE SetInitInstType
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "English"
!macro AddInstType name text
!define /IfNDef AddInstType_COUNTER 0
InstType "${text}"
!define INSTTYPE_${name}_IDX ${AddInstType_COUNTER} ; For SetCurInstType etc.
!define /ReDef /Math AddInstType_COUNTER ${AddInstType_COUNTER} + 1
!define INSTTYPE_${name}_SIN ${AddInstType_COUNTER} ; For SectionIn
!macroend
!insertmacro AddInstType ALL "Install (all)"
!insertmacro AddInstType MIN "Install (minimal)"
Section "1 (Both)" Sec1
SectionIn ${INSTTYPE_ALL_SIN} ${INSTTYPE_MIN_SIN}
SectionEnd
Section "2 (All only)" Sec2
SectionIn ${INSTTYPE_ALL_SIN}
SectionEnd
Function SetInitInstType
IfFileExists "$WinDir\Explorer.exe" 0 +2
SetCurInstType ${INSTTYPE_MIN_IDX}
FunctionEnd
Function .onInit
Call SetInitInstType ; In case installer is silent, force correct sections
FunctionEnd