DLL version 2.4 (1/4/2004)

* Initial focus is set in "initDialog" making it possible to override it from NSIS prior to calling "show"
- When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by having the text selected
- Label and other static fields no longer have State= written to the INI file when leaving the dialog
- NOTIFY flag can now be used with Link fields (State should be omitted in this case)
- Likewise, State can now be used with Button fields (behaves the same as with Link fields)
- NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when the selection changes
- Meaning of RIGHT flag is now reversed in right-to-left language mode
- HSCROLL and VSCROLL flags are no longer restricted to Text fields
- Various Link field fixes
- Text box colour bug fix


git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3350 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
eccles 2004-01-04 14:06:39 +00:00
parent 1b2abf06de
commit e1c4b80991
7 changed files with 372 additions and 273 deletions

View file

@ -1,8 +1,20 @@
DLL version 2.4 (1/4/2004)
* Initial focus is set in "initDialog" making it possible to override it from NSIS prior to calling "show"
* When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by having the text selected
* Label and other static fields no longer have State= written to the INI file when leaving the dialog
* NOTIFY flag can now be used with Link fields (State should be omitted in this case)
* Likewise, State can now be used with Button fields (behaves the same as with Link fields)
* NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when the selection changes
* Meaning of RIGHT flag is now reversed in right-to-left language mode
* HSCROLL and VSCROLL flags are no longer restricted to Text fields
* Various Link field fixes
DLL version 2.3 (12/4/2003) DLL version 2.3 (12/4/2003)
* Added new control type "Button" * Added new control type "Button"
* Added new flag "NOTIFY" * Added new flag "NOTIFY"
* Added new flag "NOWORDWRAP" for multi-line text boxes * Added new flag "NOWORDWRAP" for multi-line text boxes
* Reduced size down to 12K * Reduced size down to 12K
* Better RTL support
DLL version 2.2 (6/10/2003) DLL version 2.2 (6/10/2003)
* Added New control type LINK * Added New control type LINK

View file

@ -18,6 +18,15 @@
#include "../exdll/exdll.h" #include "../exdll/exdll.h"
#undef popstring #undef popstring
// Use for functions only called from one place to possibly reduce some code
// size. Allows the source code to remain readable by leaving the function
// intact.
#ifdef _MSC_VER
#define INLINE __forceinline
#else
#define INLINE inline
#endif
void *WINAPI MALLOC(int len) { return (void*)GlobalAlloc(GPTR,len); } void *WINAPI MALLOC(int len) { return (void*)GlobalAlloc(GPTR,len); }
void WINAPI FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); } void WINAPI FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); }
@ -62,57 +71,37 @@ char *WINAPI STRDUP(const char *c)
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// settings // settings
// crashes on windows 98 - #define IO_ENABLE_LINK
#define IO_ENABLE_LINK #define IO_ENABLE_LINK
//#define IO_LINK_UNDERLINED // Uncomment to show links text underlined //#define IO_LINK_UNDERLINED // Uncomment to show links text underlined
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// general flags // Flags
#define FLAG_RIGHT 0x00000001
// OFN_OVERWRITEPROMPT 0x00000002 // LBS_NOTIFY 0x00000001 // LISTBOX/CHECKBOX/RADIOBUTTON/BUTTON/LINK - Notify NSIS script when control is "activated" (exact meaning depends on the type of control)
// OFN_HIDEREADONLY 0x00000004 // OFN_OVERWRITEPROMPT 0x00000002 // FILEREQUEST
// OFN_HIDEREADONLY 0x00000004 // FILEREQUEST
#define FLAG_DISABLED 0x00000008 // LBS_MULTIPLESEL 0x00000008 // LISTBOX
#define FLAG_GROUP 0x00000010 #define FLAG_READONLY 0x00000010 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_NOTABSTOP 0x00000020 // BS_LEFTTEXT 0x00000020 // CHECKBOX/RADIOBUTTON
#define FLAG_PASSWORD 0x00000040 // TEXT/FILEREQUEST/DIRREQUEST
// text box flags #define FLAG_ONLYNUMBERS 0x00000080 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_PASSWORD 0x00000040 #define FLAG_MULTILINE 0x00000100 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_ONLYNUMBERS 0x00000080 #define FLAG_NOWORDWRAP 0x00000200 // TEXT/FILEREQUEST/DIRREQUEST - Disable word-wrap in multi-line text boxes
#define FLAG_MULTILINE 0x00000100 #define FLAG_WANTRETURN 0x00000400 // TEXT/FILEREQUEST/DIRREQUEST
// LBS_EXTENDEDSEL 0x00000800 // LISTBOX
// listbox flags // OFN_PATHMUSTEXIST 0x00000800 // FILEREQUEST
#define FLAG_MULTISELECT 0x00000200 // OFN_FILEMUSTEXIST 0x00001000 // FILEREQUEST
#define FLAG_EXTENDEDSEL 0x00000400 // OFN_CREATEPROMPT 0x00002000 // FILEREQUEST
#define FLAG_DROPLIST 0x00004000 // COMBOBOX
// OFN_PATHMUSTEXIST 0x00000800 #define FLAG_RESIZETOFIT 0x00008000 // BITMAP
// OFN_FILEMUSTEXIST 0x00001000 // WS_TABSTOP 0x00010000 // *ALL*
// OFN_CREATEPROMPT 0x00002000 // WS_GROUP 0x00020000 // *ALL*
#define FLAG_SAVEAS 0x00040000 // FILEREQUEST - Show "Save As" instead of "Open" for FileRequest field
// combobox flags // OFN_EXPLORER 0x00080000 // FILEREQUEST
#define FLAG_DROPLIST 0x00004000 // WS_HSCROLL 0x00100000 // *ALL*
// WS_VSCROLL 0x00200000 // *ALL*
// bitmap flags // WS_DISABLED 0x08000000 // *ALL*
#define FLAG_RESIZETOFIT 0x00008000
// general flags
#define FLAG_NOTIFY 0x00010000 // Notify NSIS script when control is "activated" (exact meaning depends on the type of control)
// browse flags
#define FLAG_SAVEAS 0x00020000 // Show "Save As" instead of "Open" for FileRequest field
// text box flags
#define FLAG_NOWORDWRAP 0x00040000 // Disable word-wrap in multi-line text boxes
// OFN_EXPLORER 0x00080000
// more text box flags
#define FLAG_WANTRETURN 0x00100000
#define FLAG_VSCROLL 0x00200000
#define FLAG_HSCROLL 0x00400000
#define FLAG_READONLY 0x00800000
struct TableEntry { struct TableEntry {
char *pszName; char *pszName;
@ -150,7 +139,7 @@ struct FieldType {
// initial buffer size. buffers will grow as required. // initial buffer size. buffers will grow as required.
// use a value larger than MAX_PATH to prevent need for excessive growing. // use a value larger than MAX_PATH to prevent need for excessive growing.
#define MAX_BUFFER_LENGTH (300) #define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
char szBrowseButtonCaption[] = "..."; char szBrowseButtonCaption[] = "...";
@ -159,7 +148,6 @@ HWND hMainWindow = NULL;
HWND hCancelButton = NULL; HWND hCancelButton = NULL;
HWND hNextButton = NULL; HWND hNextButton = NULL;
HWND hBackButton = NULL; HWND hBackButton = NULL;
HWND hInitialFocus = NULL;
HINSTANCE m_hInstance = NULL; HINSTANCE m_hInstance = NULL;
@ -197,20 +185,28 @@ LRESULT WINAPI mySendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
return SendMessage(hWnd, Msg, wParam, lParam); return SendMessage(hWnd, Msg, wParam, lParam);
} }
void WINAPI mySetFocus(HWND hWnd)
{
mySendMessage(hMainWindow, WM_NEXTDLGCTL, (WPARAM)hWnd, TRUE);
}
void WINAPI mySetWindowText(HWND hWnd, LPCTSTR pszText)
{
if (pszText)
SetWindowText(hWnd, pszText);
}
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) {
static TCHAR szDir[MAX_PATH]; static TCHAR szDir[MAX_PATH];
if (uMsg == BFFM_INITIALIZED) { if (uMsg == BFFM_INITIALIZED &&
if (GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0) { GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0)
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
} return 0;
}
return 0;
} }
bool WINAPI ValidateFields() { bool INLINE ValidateFields() {
int nIdx; int nIdx;
int nLength; int nLength;
@ -228,7 +224,7 @@ bool WINAPI ValidateFields() {
if (pField->pszValidateText) { if (pField->pszValidateText) {
MessageBox(hConfigWindow, pField->pszValidateText, NULL, MB_OK|MB_ICONWARNING); MessageBox(hConfigWindow, pField->pszValidateText, NULL, MB_OK|MB_ICONWARNING);
} }
SetFocus(pField->hwnd); mySetFocus(pField->hwnd);
return false; return false;
} }
@ -239,110 +235,111 @@ bool WINAPI ValidateFields() {
bool WINAPI SaveSettings(void) { bool WINAPI SaveSettings(void) {
static char szField[25]; static char szField[25];
int nIdx; int nBufLen = BUFFER_SIZE;
int nBufLen = MAX_BUFFER_LENGTH;
char *pszBuffer = (char*)MALLOC(nBufLen); char *pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false; if (!pszBuffer) return false;
int CurrField = 1; int nIdx;
for (nIdx = 0; nIdx < nNumFields; nIdx++) { int CurrField;
for (nIdx = 0, CurrField = 1; nIdx < nNumFields; nIdx++, CurrField++) {
FieldType *pField = pFields + nIdx; FieldType *pField = pFields + nIdx;
HWND hwnd = pField->hwnd; HWND hwnd = pField->hwnd;
switch (pField->nType) { switch (pField->nType) {
case FIELD_BROWSEBUTTON: case FIELD_BROWSEBUTTON:
if (g_NotifyField > CurrField) if (g_NotifyField > CurrField)
--g_NotifyField; --g_NotifyField;
--CurrField;
default:
continue; continue;
case FIELD_INVALID:
case FIELD_LABEL:
case FIELD_BUTTON:
*pszBuffer=0;
break;
case FIELD_CHECKBOX: case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON: case FIELD_RADIOBUTTON:
wsprintf(pszBuffer, "%d", !!mySendMessage(hwnd, BM_GETCHECK, 0, 0)); wsprintf(pszBuffer, "%d", !!mySendMessage(hwnd, BM_GETCHECK, 0, 0));
break; break;
case FIELD_LISTBOX: case FIELD_LISTBOX:
{ {
// Ok, this one requires a bit of work. // Ok, this one requires a bit of work.
// First, we allocate a buffer long enough to hold every item. // First, we allocate a buffer long enough to hold every item.
// Then, we loop through every item and if it's selected we add it to our buffer. // Then, we loop through every item and if it's selected we add it to our buffer.
// If there is already an item in the list, then we prepend a | character before the new item. // If there is already an item in the list, then we prepend a | character before the new item.
// We could simplify for single-select boxes, but using one piece of code saves some space. // We could simplify for single-select boxes, but using one piece of code saves some space.
int nLength = lstrlen(pField->pszListItems) + 10; int nLength = lstrlen(pField->pszListItems) + 10;
if (nLength > nBufLen) { if (nLength > nBufLen) {
FREE(pszBuffer); FREE(pszBuffer);
nBufLen = nLength; nBufLen = nLength;
pszBuffer = (char*)MALLOC(nBufLen); pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false; if (!pszBuffer) return false;
} }
char *pszItem = (char*)MALLOC(nBufLen); char *pszItem = (char*)MALLOC(nBufLen);
if (!pszItem) return false; if (!pszItem) return false;
*pszBuffer = '\0'; *pszBuffer = '\0';
int nNumItems = mySendMessage(hwnd, LB_GETCOUNT, 0, 0); int nNumItems = mySendMessage(hwnd, LB_GETCOUNT, 0, 0);
for (int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) { for (int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) {
if (mySendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) { if (mySendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) {
if (*pszBuffer) lstrcat(pszBuffer, "|"); if (*pszBuffer) lstrcat(pszBuffer, "|");
mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem); mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem);
lstrcat(pszBuffer, pszItem); lstrcat(pszBuffer, pszItem);
}
}
FREE(pszItem);
break;
}
case FIELD_TEXT:
case FIELD_FILEREQUEST:
case FIELD_DIRREQUEST:
case FIELD_COMBOBOX:
{
int nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0);
if (nLength > nBufLen) {
FREE(pszBuffer);
// add a bit extra so we do this less often
nBufLen = nLength + 20;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
*pszBuffer='"';
GetWindowText(hwnd, pszBuffer+1, nBufLen-1);
pszBuffer[nLength+1]='"';
pszBuffer[nLength+2]='\0';
if ( pField->nType == FIELD_TEXT && (pField->nFlags & FLAG_MULTILINE) )
{
char *pszBuf2 = (char*)MALLOC(nBufLen*2); // double the size, consider the worst case, all chars are \r\n
char *p1, *p2;
for (p1=pszBuffer,p2=pszBuf2; *p1; p1++, p2++) {
switch (*p1) {
case '\t':
*p2++ = '\\';
*p2 = 't';
break;
case '\n':
*p2++ = '\\';
*p2 = 'n';
break;
case '\r':
*p2++ = '\\';
*p2 = 'r';
break;
case '\\':
*p2++ = '\\';
default:
*p2=*p1;
} }
} }
*p2 = 0;
FREE(pszItem); nBufLen = nBufLen*2;
break; FREE(pszBuffer);
} pszBuffer=pszBuf2;
default:
{
int nLength = mySendMessage(pField->hwnd, WM_GETTEXTLENGTH, 0, 0);
if (nLength > nBufLen) {
FREE(pszBuffer);
// add a bit extra so we do this less often
nBufLen = nLength + 20;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
*pszBuffer='"';
GetWindowText(hwnd, pszBuffer+1, nBufLen-1);
pszBuffer[nLength+1]='"';
pszBuffer[nLength+2]='\0';
if ( pField->nType == FIELD_TEXT && pField->nFlags & FLAG_MULTILINE )
{
char *pszBuf2 = (char*)MALLOC(nBufLen*2); // double the size, consider the worst case, all chars are \r\n
char *p1, *p2;
for (p1=pszBuffer,p2=pszBuf2; *p1; p1++, p2++) {
switch (*p1) {
case '\r':
*p2++ = '\\';
*p2 = 'r';
break;
case '\n':
*p2++ = '\\';
*p2 = 'n';
break;
case '\t':
*p2++ = '\\';
*p2 = 't';
break;
case '\\':
*p2++ = '\\';
default:
*p2=*p1;
}
}
*p2 = 0;
nBufLen = nBufLen*2;
FREE(pszBuffer);
pszBuffer=pszBuf2;
}
break;
} }
break;
}
} }
wsprintf(szField, "Field %d", CurrField); wsprintf(szField, "Field %d", CurrField);
WritePrivateProfileString(szField, "State", pszBuffer, pszFilename); WritePrivateProfileString(szField, "State", pszBuffer, pszFilename);
CurrField++;
} }
// Tell NSIS which control was activated, if any // Tell NSIS which control was activated, if any
@ -356,7 +353,6 @@ bool WINAPI SaveSettings(void) {
#define BROWSE_WIDTH 15 #define BROWSE_WIDTH 15
#define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
static char szResult[BUFFER_SIZE]; static char szResult[BUFFER_SIZE];
DWORD WINAPI myGetProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName) DWORD WINAPI myGetProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName)
@ -432,59 +428,52 @@ int WINAPI ReadSettings(void) {
}; };
// Control flags // Control flags
static TableEntry FlagTable[] = { static TableEntry FlagTable[] = {
{ "RIGHT", FLAG_RIGHT }, { "NOTIFY", LBS_NOTIFY },
{ "WARN_IF_EXIST", OFN_OVERWRITEPROMPT }, { "WARN_IF_EXIST", OFN_OVERWRITEPROMPT },
{ "FILE_HIDEREADONLY", OFN_HIDEREADONLY }, { "FILE_HIDEREADONLY", OFN_HIDEREADONLY },
{ "DISABLED", FLAG_DISABLED }, { "MULTISELECT", LBS_MULTIPLESEL },
{ "GROUP", FLAG_GROUP }, { "READONLY", FLAG_READONLY },
{ "NOTABSTOP", FLAG_NOTABSTOP }, { "RIGHT", BS_LEFTTEXT },
{ "PASSWORD", FLAG_PASSWORD }, { "PASSWORD", FLAG_PASSWORD },
{ "ONLY_NUMBERS", FLAG_ONLYNUMBERS }, { "ONLY_NUMBERS", FLAG_ONLYNUMBERS },
{ "MULTILINE", FLAG_MULTILINE }, { "MULTILINE", FLAG_MULTILINE },
{ "MULTISELECT", FLAG_MULTISELECT }, { "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "EXTENDEDSELCT", FLAG_EXTENDEDSEL }, { "WANTRETURN", FLAG_WANTRETURN },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST }, { "EXTENDEDSELCT", LBS_EXTENDEDSEL },
{ "PATH_MUST_EXIST", OFN_PATHMUSTEXIST }, { "PATH_MUST_EXIST", OFN_PATHMUSTEXIST },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST },
{ "PROMPT_CREATE", OFN_CREATEPROMPT }, { "PROMPT_CREATE", OFN_CREATEPROMPT },
{ "DROPLIST", FLAG_DROPLIST }, { "DROPLIST", FLAG_DROPLIST },
{ "RESIZETOFIT", FLAG_RESIZETOFIT }, { "RESIZETOFIT", FLAG_RESIZETOFIT },
{ "NOTIFY", FLAG_NOTIFY }, { "NOTABSTOP", WS_TABSTOP },
{ "GROUP", WS_GROUP },
{ "REQ_SAVE", FLAG_SAVEAS }, { "REQ_SAVE", FLAG_SAVEAS },
{ "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "FILE_EXPLORER", OFN_EXPLORER }, { "FILE_EXPLORER", OFN_EXPLORER },
{ "WANTRETURN", FLAG_WANTRETURN }, { "HSCROLL", WS_HSCROLL },
{ "VSCROLL", FLAG_VSCROLL }, { "VSCROLL", WS_VSCROLL },
{ "HSCROLL", FLAG_HSCROLL }, { "DISABLED", WS_DISABLED },
{ "READONLY", FLAG_READONLY },
{ NULL, 0 } { NULL, 0 }
}; };
FieldType *pField = pFields + nIdx; FieldType *pField = pFields + nIdx;
wsprintf(szField, "Field %d", nCtrlIdx + 1); wsprintf(szField, "Field %d", nCtrlIdx + 1);
myGetProfileString(szField, "TYPE");
// Get the control type // Get the control type
myGetProfileString(szField, "TYPE");
pField->nType = LookupToken(TypeTable, szResult); pField->nType = LookupToken(TypeTable, szResult);
if (pField->nType == FIELD_INVALID) if (pField->nType == FIELD_INVALID)
continue; continue;
// Lookup flags associated with the control type // Lookup flags associated with the control type
pField->nFlags |= LookupToken(FlagTable, szResult); pField->nFlags = LookupToken(FlagTable, szResult);
myGetProfileString(szField, "Flags");
pField->pszText = myGetProfileStringDup(szField, "TEXT"); pField->nFlags |= LookupTokens(FlagTable, szResult);
// Label Text - convert newline
if (pField->nType == FIELD_LABEL) {
ConvertNewLines(pField->pszText);
}
// pszState must not be NULL! // pszState must not be NULL!
myGetProfileString(szField, "State"); myGetProfileString(szField, "State");
pField->pszState = strdup(szResult); pField->pszState = strdup(szResult);
pField->pszRoot = myGetProfileStringDup(szField, "ROOT"); // ListBox items list
{ {
int nResult = myGetProfileString(szField, "ListItems"); int nResult = myGetProfileString(szField, "ListItems");
if (nResult) { if (nResult) {
@ -495,21 +484,24 @@ int WINAPI ReadSettings(void) {
pField->pszListItems[nResult + 1] = '\0'; pField->pszListItems[nResult + 1] = '\0';
} }
} }
pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0);
pField->nMinLength = myGetProfileInt(szField, "MinLen", 0);
pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText"); // Label Text - convert newline
pField->pszText = myGetProfileStringDup(szField, "TEXT");
if (pField->nType == FIELD_LABEL)
ConvertNewLines(pField->pszText);
// Dir request - root folder
pField->pszRoot = myGetProfileStringDup(szField, "ROOT");
// ValidateText - convert newline // ValidateText - convert newline
pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText");
if (pField->pszValidateText) { ConvertNewLines(pField->pszValidateText);
ConvertNewLines(pField->pszValidateText);
}
{ {
int nResult = GetPrivateProfileString(szField, "Filter", "All Files|*.*", szResult, sizeof(szResult), pszFilename); int nResult = GetPrivateProfileString(szField, "Filter", "All Files|*.*", szResult, sizeof(szResult), pszFilename);
if (nResult) { if (nResult) {
// add an extra | character to the end to simplify the loop where we add the items. // Convert the filter to the format required by Windows: NULL after each
// item followed by a terminating NULL
pField->pszFilter = (char*)MALLOC(nResult + 2); pField->pszFilter = (char*)MALLOC(nResult + 2);
strcpy(pField->pszFilter, szResult); strcpy(pField->pszFilter, szResult);
char *pszPos = pField->pszFilter; char *pszPos = pField->pszFilter;
@ -521,15 +513,13 @@ int WINAPI ReadSettings(void) {
} }
pField->rect.left = myGetProfileInt(szField, "LEFT", 0); pField->rect.left = myGetProfileInt(szField, "LEFT", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.top = myGetProfileInt(szField, "TOP", 0); pField->rect.top = myGetProfileInt(szField, "TOP", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.bottom = myGetProfileInt(szField, "BOTTOM", 0); pField->rect.bottom = myGetProfileInt(szField, "BOTTOM", 0);
pField->nMinLength = myGetProfileInt(szField, "MinLen", 0);
myGetProfileString(szField, "Flags"); pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0);
pField->nFlags |= LookupTokens(FlagTable, szResult);
// Text color for LINK control, default is pure blue // Text color for LINK control, default is pure blue
//if (pField->nType == FIELD_LINK)
pField->hImage = (HANDLE)myGetProfileInt(szField, "TxtColor", RGB(0,0,255)); pField->hImage = (HANDLE)myGetProfileInt(szField, "TxtColor", RGB(0,0,255));
pField->nControlID = 1200 + nIdx; pField->nControlID = 1200 + nIdx;
@ -538,7 +528,7 @@ int WINAPI ReadSettings(void) {
FieldType *pNewField = &pFields[nIdx+1]; FieldType *pNewField = &pFields[nIdx+1];
pNewField->nControlID = 1200 + nIdx + 1; pNewField->nControlID = 1200 + nIdx + 1;
pNewField->nType = FIELD_BROWSEBUTTON; pNewField->nType = FIELD_BROWSEBUTTON;
pNewField->nFlags = pField->nFlags & (FLAG_DISABLED | FLAG_NOTABSTOP); pNewField->nFlags = pField->nFlags & (WS_DISABLED | WS_TABSTOP);
pNewField->pszText = STRDUP(szBrowseButtonCaption); // needed for generic FREE pNewField->pszText = STRDUP(szBrowseButtonCaption); // needed for generic FREE
pNewField->rect.right = pField->rect.right; pNewField->rect.right = pField->rect.right;
pNewField->rect.left = pNewField->rect.right - BROWSE_WIDTH; pNewField->rect.left = pNewField->rect.right - BROWSE_WIDTH;
@ -556,7 +546,9 @@ int WINAPI ReadSettings(void) {
LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify) { LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify) {
switch (codeNotify) { switch (codeNotify) {
case BN_CLICKED: case BN_CLICKED: // The user pressed a button
case LBN_SELCHANGE: // The user changed the selection in a ListBox control
// case CBN_SELCHANGE: // The user changed the selection in a DropList control (same value as LBN_SELCHANGE)
{ {
char szBrowsePath[MAX_PATH]; char szBrowsePath[MAX_PATH];
int nIdx = FindControlIdx(id); int nIdx = FindControlIdx(id);
@ -580,7 +572,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
tryagain: tryagain:
if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) { if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) {
SetWindowText(pField->hwnd, szBrowsePath); mySetWindowText(pField->hwnd, szBrowsePath);
break; break;
} }
else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) { else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) {
@ -625,7 +617,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
break; break;
if (SHGetPathFromIDList(pResult, szBrowsePath)) { if (SHGetPathFromIDList(pResult, szBrowsePath)) {
SetWindowText(pField->hwnd, szBrowsePath); mySetWindowText(pField->hwnd, szBrowsePath);
} }
LPMALLOC pMalloc; LPMALLOC pMalloc;
@ -637,16 +629,20 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
} }
case FIELD_LINK: case FIELD_LINK:
ShellExecute(hMainWindow, NULL, pField->pszState, NULL, NULL, SW_SHOWDEFAULT); case FIELD_BUTTON:
// Allow the state to be empty - this might be useful in conjunction
// with the NOTIFY flag
if (*pField->pszState)
ShellExecute(hMainWindow, NULL, pField->pszState, NULL, NULL, SW_SHOWDEFAULT);
break; break;
} }
if (pField->nFlags & FLAG_NOTIFY) { if (pField->nFlags & LBS_NOTIFY) {
// Remember which control was activated then pretend the user clicked Next // Remember which control was activated then pretend the user clicked Next
g_NotifyField = nIdx + 1; g_NotifyField = nIdx + 1;
// the next button must be enabled or nsis will ignore WM_COMMAND // the next button must be enabled or nsis will ignore WM_COMMAND
BOOL bWasDisabled = EnableWindow(hNextButton, TRUE); BOOL bWasDisabled = EnableWindow(hNextButton, TRUE);
FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, codeNotify, mySendMessage); FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, BN_CLICKED, mySendMessage);
if (bWasDisabled) if (bWasDisabled)
EnableWindow(hNextButton, FALSE); EnableWindow(hNextButton, FALSE);
} }
@ -715,13 +711,12 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
// We need lpdis->rcItem later // We need lpdis->rcItem later
RECT rc = lpdis->rcItem; RECT rc = lpdis->rcItem;
// Get TxtColor unless the user has set another using SetCtlColors
if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
SetTextColor(lpdis->hDC, (COLORREF) pField->hImage);
// Calculate needed size of the control // Calculate needed size of the control
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_VCENTER | DT_SINGLELINE | DT_CALCRECT); DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_VCENTER | DT_SINGLELINE | DT_CALCRECT);
// Make some more room so the focus rect won't cut letters off
rc.right = min(rc.right + 2, lpdis->rcItem.right);
// Move rect to right if in RTL mode // Move rect to right if in RTL mode
if (bRTL) if (bRTL)
{ {
@ -729,19 +724,24 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
rc.right += lpdis->rcItem.right - rc.right; rc.right += lpdis->rcItem.right - rc.right;
} }
// Make some more room so the focus rect won't cut letters off if (lpdis->itemAction & ODA_DRAWENTIRE)
rc.right = min(rc.right + 2, lpdis->rcItem.right); {
// Get TxtColor unless the user has set another using SetCtlColors
if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
SetTextColor(lpdis->hDC, (COLORREF) pField->hImage);
// Draw the text // Draw the text
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0)); DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0));
}
// Draw the focus rect if needed // Draw the focus rect if needed
if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS) || (lpdis->itemAction & ODA_SELECT)) if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS))
{ {
// NB: when not in DRAWENTIRE mode, this will actually toggle the focus
// rectangle since it's drawn in a XOR way
DrawFocusRect(lpdis->hDC, &rc); DrawFocusRect(lpdis->hDC, &rc);
} }
MapWindowPoints(lpdis->hwndItem, 0, (LPPOINT) &rc, 2);
pField->rect = rc; pField->rect = rc;
#ifdef IO_LINK_UNDERLINED #ifdef IO_LINK_UNDERLINED
@ -755,7 +755,7 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_CTLCOLORBTN: case WM_CTLCOLORBTN:
case WM_CTLCOLORLISTBOX: case WM_CTLCOLORLISTBOX:
// let the NSIS window handle colors, it knows best // let the NSIS window handle colors, it knows best
return mySendMessage(hMainWindow, WM_CTLCOLORSTATIC, wParam, lParam); return mySendMessage(hMainWindow, uMsg, wParam, lParam);
} }
return 0; return 0;
} }
@ -766,31 +766,44 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
#define IDC_HAND MAKEINTRESOURCE(32649) #define IDC_HAND MAKEINTRESOURCE(32649)
#endif #endif
#ifndef BS_TYPEMASK
#define BS_TYPEMASK 0x0000000FL
#endif
// pFields[nIdx].nParentIdx is used to store original windowproc // pFields[nIdx].nParentIdx is used to store original windowproc
int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lParam) int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lParam)
{ {
int CtrlId = GetDlgCtrlID(hWin); int StaticField = FindControlIdx(GetDlgCtrlID(hWin));
int StaticField = FindControlIdx(CtrlId);
if (StaticField < 0) if (StaticField < 0)
return 0; return 0;
FieldType *pField = pFields + StaticField; FieldType *pField = pFields + StaticField;
switch(uMsg) switch(uMsg)
{ {
case WM_SETFOCUS: case WM_GETDLGCODE:
mySendMessage(hConfigWindow, DM_SETDEFID, CtrlId, 0); // Pretend we are a normal button/default button as appropriate
// remove the BS_DEFPUSHBUTTON style from IDOK return DLGC_BUTTON | ((pField->nFlags & FLAG_WANTRETURN) ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
mySendMessage(GetDlgItem(hMainWindow, IDOK), BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
break; case BM_SETSTYLE:
case WM_NCHITTEST: // Detect when we are becoming the default button but don't lose the owner-draw style
if ((wParam & BS_TYPEMASK) == BS_DEFPUSHBUTTON)
pField->nFlags |= FLAG_WANTRETURN; // Hijack this flag to indicate default button status
else
pField->nFlags &= ~FLAG_WANTRETURN;
wParam = (wParam & ~BS_TYPEMASK) | BS_OWNERDRAW;
break;
case WM_NCHITTEST:
{ {
POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
MapWindowPoints(0, hWin, &pt, 1);
if (PtInRect(&pField->rect, pt)) if (PtInRect(&pField->rect, pt))
return HTCLIENT; return HTCLIENT;
else else
return HTNOWHERE; return HTNOWHERE;
} }
case WM_SETCURSOR:
case WM_SETCURSOR:
{ {
if ((HWND)wParam == hWin && LOWORD(lParam) == HTCLIENT) if ((HWND)wParam == hWin && LOWORD(lParam) == HTCLIENT)
{ {
@ -838,12 +851,12 @@ int WINAPI createCfgDlg()
} }
hCancelButton = GetDlgItem(mainwnd,IDCANCEL); hCancelButton = GetDlgItem(mainwnd,IDCANCEL);
hInitialFocus = hNextButton = GetDlgItem(mainwnd,IDOK); hNextButton = GetDlgItem(mainwnd,IDOK);
hBackButton = GetDlgItem(mainwnd,3); hBackButton = GetDlgItem(mainwnd,3);
if (pszCancelButtonText) SetWindowText(hCancelButton,pszCancelButtonText); mySetWindowText(hCancelButton,pszCancelButtonText);
if (pszNextButtonText) SetWindowText(hNextButton,pszNextButtonText); mySetWindowText(hNextButton,pszNextButtonText);
if (pszBackButtonText) SetWindowText(hBackButton,pszBackButtonText); mySetWindowText(hBackButton,pszBackButtonText);
if (bBackEnabled!=-1) EnableWindow(hBackButton,bBackEnabled); if (bBackEnabled!=-1) EnableWindow(hBackButton,bBackEnabled);
if (bCancelEnabled!=-1) EnableWindow(hCancelButton,bCancelEnabled); if (bCancelEnabled!=-1) EnableWindow(hCancelButton,bCancelEnabled);
@ -894,6 +907,8 @@ int WINAPI createCfgDlg()
DeleteDC(memDC); DeleteDC(memDC);
BOOL fFocused = FALSE;
#define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) #define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
for (int nIdx = 0; nIdx < nNumFields; nIdx++) { for (int nIdx = 0; nIdx < nNumFields; nIdx++) {
@ -905,18 +920,18 @@ int WINAPI createCfgDlg()
DWORD dwRTLExStyle; DWORD dwRTLExStyle;
} ClassTable[] = { } ClassTable[] = {
{ "STATIC", // FIELD_LABEL { "STATIC", // FIELD_LABEL
DEFAULT_STYLES /*| WS_TABSTOP*/, DEFAULT_STYLES,
DEFAULT_STYLES | SS_RIGHT /*| WS_TABSTOP*/, DEFAULT_STYLES | SS_RIGHT,
WS_EX_TRANSPARENT, WS_EX_TRANSPARENT,
WS_EX_TRANSPARENT | WS_EX_RTLREADING }, WS_EX_TRANSPARENT | WS_EX_RTLREADING },
{ "STATIC", // FIELD_ICON { "STATIC", // FIELD_ICON
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON, DEFAULT_STYLES | SS_ICON,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON, DEFAULT_STYLES | SS_ICON,
0, 0,
WS_EX_RTLREADING }, WS_EX_RTLREADING },
{ "STATIC", // FIELD_BITMAP { "STATIC", // FIELD_BITMAP
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE, DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE, DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
0, 0,
WS_EX_RTLREADING }, WS_EX_RTLREADING },
{ "BUTTON", // FIELD_BROWSEBUTTON { "BUTTON", // FIELD_BROWSEBUTTON
@ -1025,9 +1040,7 @@ int WINAPI createCfgDlg()
break; break;
case FIELD_CHECKBOX: case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON: case FIELD_RADIOBUTTON:
case FIELD_BUTTON: dwStyle ^= pField->nFlags & BS_LEFTTEXT;
if (pField->nFlags & FLAG_RIGHT)
dwStyle |= BS_RIGHTBUTTON;
break; break;
case FIELD_TEXT: case FIELD_TEXT:
case FIELD_FILEREQUEST: case FIELD_FILEREQUEST:
@ -1036,40 +1049,37 @@ int WINAPI createCfgDlg()
dwStyle |= ES_PASSWORD; dwStyle |= ES_PASSWORD;
if (pField->nFlags & FLAG_ONLYNUMBERS) if (pField->nFlags & FLAG_ONLYNUMBERS)
dwStyle |= ES_NUMBER; dwStyle |= ES_NUMBER;
if (pField->nFlags & FLAG_WANTRETURN)
dwStyle |= ES_WANTRETURN;
if (pField->nFlags & FLAG_READONLY)
dwStyle |= ES_READONLY;
title = pField->pszState;
if (pField->nFlags & FLAG_MULTILINE) if (pField->nFlags & FLAG_MULTILINE)
{ {
dwStyle |= ES_MULTILINE | ES_AUTOVSCROLL; dwStyle |= ES_MULTILINE | ES_AUTOVSCROLL;
// Enable word-wrap unless we have a horizontal scroll bar // Enable word-wrap unless we have a horizontal scroll bar
// or it has been explicitly disallowed // or it has been explicitly disallowed
if (!(pField->nFlags & (FLAG_HSCROLL | FLAG_NOWORDWRAP))) if (!(pField->nFlags & (WS_HSCROLL | FLAG_NOWORDWRAP)))
dwStyle &= ~ES_AUTOHSCROLL; dwStyle &= ~ES_AUTOHSCROLL;
ConvertNewLines(pField->pszState); ConvertNewLines(pField->pszState);
// If multiline-readonly then hold the text back until after the
// initial focus has been set. This is so the text is not initially
// selected - useful for License Page look-a-likes.
if (pField->nFlags & FLAG_READONLY)
title = NULL;
} }
if (pField->nFlags & FLAG_WANTRETURN)
dwStyle |= ES_WANTRETURN;
if (pField->nFlags & FLAG_VSCROLL)
dwStyle |= WS_VSCROLL;
if (pField->nFlags & FLAG_HSCROLL)
dwStyle |= WS_HSCROLL;
if (pField->nFlags & FLAG_READONLY)
dwStyle |= ES_READONLY;
title = pField->pszState;
break; break;
case FIELD_COMBOBOX: case FIELD_COMBOBOX:
dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN; dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN;
title = pField->pszState; title = pField->pszState;
break; break;
case FIELD_LISTBOX: case FIELD_LISTBOX:
if (pField->nFlags & FLAG_EXTENDEDSEL) dwStyle |= pField->nFlags & (LBS_NOTIFY | LBS_MULTIPLESEL | LBS_EXTENDEDSEL);
dwStyle |= LBS_EXTENDEDSEL;
if (pField->nFlags & FLAG_MULTISELECT)
dwStyle |= LBS_MULTIPLESEL;
break; break;
} }
if (pField->nFlags & FLAG_DISABLED) dwStyle |= WS_DISABLED; dwStyle |= pField->nFlags & (WS_GROUP | WS_HSCROLL | WS_VSCROLL | WS_DISABLED);
if (pField->nFlags & FLAG_GROUP) dwStyle |= WS_GROUP; if (pField->nFlags & WS_TABSTOP) dwStyle &= ~WS_TABSTOP;
if (pField->nFlags & FLAG_NOTABSTOP) dwStyle &= ~WS_TABSTOP;
HWND hwCtrl = pField->hwnd = CreateWindowEx( HWND hwCtrl = pField->hwnd = CreateWindowEx(
dwExStyle, dwExStyle,
@ -1090,15 +1100,20 @@ int WINAPI createCfgDlg()
// Sets the font of IO window to be the same as the main window // Sets the font of IO window to be the same as the main window
mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE); mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE);
// Set initial focus to the first appropriate field // Set initial focus to the first appropriate field
if ((hInitialFocus == hNextButton) && (dwStyle & WS_TABSTOP)) if (!fFocused && (dwStyle & (WS_TABSTOP | WS_DISABLED)) == WS_TABSTOP) {
hInitialFocus = hwCtrl; fFocused = TRUE;
mySetFocus(hwCtrl);
}
// make sure we created the window, then set additional attributes // make sure we created the window, then set additional attributes
switch (pField->nType) { switch (pField->nType) {
case FIELD_TEXT: case FIELD_TEXT:
mySendMessage(hwCtrl, WM_SETTEXT, 0, (LPARAM)title);
// no break;
case FIELD_FILEREQUEST: case FIELD_FILEREQUEST:
case FIELD_DIRREQUEST: case FIELD_DIRREQUEST:
// If multiline-readonly then hold the text back until after the
// initial focus has been set. This is so the text is not initially
// selected - useful for License Page look-a-likes.
if ((pField->nFlags & (FLAG_MULTILINE | FLAG_READONLY)) == (FLAG_MULTILINE | FLAG_READONLY))
mySetWindowText(hwCtrl, pField->pszState);
mySendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pField->nMaxLength, (LPARAM)0); mySendMessage(hwCtrl, EM_LIMITTEXT, (WPARAM)pField->nMaxLength, (LPARAM)0);
break; break;
@ -1139,7 +1154,7 @@ int WINAPI createCfgDlg()
} }
FREE(pszList); FREE(pszList);
if (pField->pszState) { if (pField->pszState) {
if (pField->nFlags & (FLAG_MULTISELECT|FLAG_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) { if (pField->nFlags & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && nFindMsg == LB_FINDSTRINGEXACT) {
mySendMessage(hwCtrl, LB_SETSEL, FALSE, -1); mySendMessage(hwCtrl, LB_SETSEL, FALSE, -1);
pszStart = pszEnd = pField->pszState; pszStart = pszEnd = pField->pszState;
while (*pszStart) { while (*pszStart) {
@ -1212,8 +1227,10 @@ int WINAPI createCfgDlg()
} }
} }
if (pszTitle) if (!fFocused)
SetWindowText(mainwnd,pszTitle); mySetFocus(hNextButton);
mySetWindowText(mainwnd,pszTitle);
pFilenameStackEntry = *g_stacktop; pFilenameStackEntry = *g_stacktop;
*g_stacktop = (*g_stacktop)->next; *g_stacktop = (*g_stacktop)->next;
static char tmp[32]; static char tmp[32];
@ -1229,7 +1246,6 @@ void WINAPI showCfgDlg()
// Tell NSIS to remove old inner dialog and pass handle of the new inner dialog // Tell NSIS to remove old inner dialog and pass handle of the new inner dialog
mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0); mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0);
ShowWindow(hConfigWindow, SW_SHOWNA); ShowWindow(hConfigWindow, SW_SHOWNA);
SetFocus(hInitialFocus);
g_done = g_NotifyField = 0; g_done = g_NotifyField = 0;
@ -1364,15 +1380,15 @@ void WINAPI ConvertNewLines(char *str) {
for (p1=p2=str; *p1; p1++, p2++) { for (p1=p2=str; *p1; p1++, p2++) {
if (*p1 == '\\') { if (*p1 == '\\') {
switch (p1[1]) { switch (p1[1]) {
case 't':
*p2 = '\t';
break;
case 'n': case 'n':
*p2 = '\n'; *p2 = '\n';
break; break;
case 'r': case 'r':
*p2 = '\r'; *p2 = '\r';
break; break;
case 't':
*p2 = '\t';
break;
case '\\': case '\\':
*p2 = '\\'; *p2 = '\\';
break; break;

View file

@ -235,10 +235,12 @@ will display a directory requester where the user can browse for a directory.<br
An "<em>Icon</em>" control displays an icon. Use no Text to use the installer icon.<br /> An "<em>Icon</em>" control displays an icon. Use no Text to use the installer icon.<br />
A "<em>Bitmap</em>" control displays a bitmap.<br /> A "<em>Bitmap</em>" control displays a bitmap.<br />
A "<em>GroupBox</em>" control displays a frame to group controls.<br /> A "<em>GroupBox</em>" control displays a frame to group controls.<br />
A "<em>Link</em>" control displays a static hot text, when the user click the control the contents A "<em>Link</em>" control displays a static hot text. When the user clicks the control the contents
of <strong>State</strong> (e.g. http://...) will be executed using ShellExecute<br /> of <strong>State</strong> (e.g. http://...) will be executed using ShellExecute. Alternatively
A "<em>Button</em>" control displays a push button that your NSIS script can act on when pressed. <strong>State</strong> can be omitted and the <em>NOTIFY</em> flag used to have your NSIS script
See the "<em>NOTIFY</em>" flag for more information.</td> called. See the "<em>NOTIFY</em>" flag below for more information.<br />
A "<em>Button</em>" control displays a push button that can be used in the same way as the
"<em>Link</em>" control above.</td>
</tr> </tr>
<tr> <tr>
<td class="lefttable"><strong>Text</strong></td> <td class="lefttable"><strong>Text</strong></td>
@ -257,7 +259,8 @@ are NSIS functions for converting text to/from this format.</td>
window, so you can read from it from NSIS. For edit texts and dir and file request boxes, this is window, so you can read from it from NSIS. For edit texts and dir and file request boxes, this is
the string that is specified. For radio button and check boxes, this can be '0' or '1' (for the string that is specified. For radio button and check boxes, this can be '0' or '1' (for
unchecked or checked). For list boxes, combo boxes and drop lists this is the selected items unchecked or checked). For list boxes, combo boxes and drop lists this is the selected items
separated by pipes ('|').<br /> separated by pipes ('|'). For Links and Buttons this can specify something to be executed or opened
(using ShellExecute).<br />
<br /> <br />
<strong>Note:</strong> For Text fields with the MULTILINE flag, \r\n will be converted to a <strong>Note:</strong> For Text fields with the MULTILINE flag, \r\n will be converted to a
newline. To use a back-slash in your text you have to escape it using another back-slash - \\. newline. To use a back-slash in your text you have to escape it using another back-slash - \\.
@ -314,16 +317,19 @@ Bottom</strong></td>
set in dialog units. To get the right dimensions for your controls, design your dialog using a set in dialog units. To get the right dimensions for your controls, design your dialog using a
resource editor and copy the dimensions to the INI file.<br /> resource editor and copy the dimensions to the INI file.<br />
<br /> <br />
<strong>Note:</strong> For combobox or droplist, the "<em>bottom</em>" value is not used in the <strong>Note:</strong> You can specify negative coordinates to specify the distance from the right
or bottom edge.<br />
<br />
<strong>Note (2):</strong> For combobox or droplist, the "<em>bottom</em>" value is not used in the
same way.<br /> same way.<br />
In this case, the bottom value is the maximum size of the window when the pop-up list is being In this case, the bottom value is the maximum size of the window when the pop-up list is being
displayed. All other times, the combobox is automatically sized to be one element tall. If you have displayed. All other times, the combobox is automatically sized to be one element tall. If you have
trouble where you can not see the combobox drop-down, then check the bottom value and ensure it is trouble where you can not see the combobox drop-down, then check the bottom value and ensure it is
large enough.<br /> large enough. A rough guide for the height required is the number of items in the list multiplied
by 8, plus 20.<br />
<br /> <br />
<strong>Note (2):</strong> FileRequest and DirRequest controls will allocate 15 dialog units to the <strong>Note (3):</strong> FileRequest and DirRequest controls will allocate 15 dialog units to the
browse button. Make this control wide enough the contents of the textbox can be seen. Note that you browse button. Make this control wide enough the contents of the textbox can be seen.</td>
can specify negative coordinates to specify the distance from the right or bottom edge.</td>
</tr> </tr>
<tr> <tr>
<td class="lefttable"><strong>Filter</strong></td> <td class="lefttable"><strong>Filter</strong></td>
@ -461,13 +467,12 @@ HSCROLL flag also has this effect.</td>
</tr> </tr>
<tr> <tr>
<td class="righttable">HSCROLL</td> <td class="righttable">HSCROLL</td>
<td class="righttable">Used by "<em>Text</em>" controls with multiple-line. Show a horizontal <td class="righttable">Show a horizontal scrollbar. When used by "<em>Text</em>" controls with
scrollbar and disable word-wrap.</td> multiple-lines this also disables word-wrap.</td>
</tr> </tr>
<tr> <tr>
<td class="righttable">VSCROLL</td> <td class="righttable">VSCROLL</td>
<td class="righttable">Used by "<em>Text</em>" controls with multiple-line. Show a vertical <td class="righttable">Show a vertical scrollbar.</td>
scrollbar.</td>
</tr> </tr>
<tr> <tr>
<td class="righttable">READONLY</td> <td class="righttable">READONLY</td>
@ -476,11 +481,12 @@ text in the edit control, but allow the user to select and copy the text.</td>
</tr> </tr>
<tr> <tr>
<td class="righttable">NOTIFY</td> <td class="righttable">NOTIFY</td>
<td class="righttable">Used by "<em>Button</em>", "<em>CheckBox</em>" and "<em>RadioButton</em>" <td class="righttable">Used by "<em>Button</em>", "<em>Link</em>", "<em>CheckBox</em>",
controls. Causes InstallOptions to call your NSIS custom page validation/leave function whenever "<em>RadioButton</em>", "<em>ListBox</em>" and "<em>DropList</em>" controls. Causes InstallOptions
the button is pressed. Your validation/leave function can read the "<em>State</em>" value from the to call your NSIS custom page validation/leave function whenever the control's selection changes.
"<em>Settings</em>" section to determine which custom button has been pressed, if any, and perform Your validation/leave function can read the "<em>State</em>" value from the "<em>Settings</em>"
some appropriate action followed by an Abort instruction (to tell NSIS to return to the page). The section to determine which control caused the notification, if any, and perform some appropriate
action followed by an Abort instruction (to tell NSIS to return to the page). The
Contrib\InstallOptions folder contains an example script showing how this might be used.</td> Contrib\InstallOptions folder contains an example script showing how this might be used.</td>
</tr> </tr>
</table> </table>
@ -718,12 +724,32 @@ FunctionEnd
</pre> </pre>
<h2>Version history</h2> <h2>Version history</h2>
<ul> <ul>
<li>DLL version 2.4 (1/4/2004)
<ul>
<li>Initial focus is set in "initDialog" making it possible to override it from NSIS prior to
calling "show"</li>
<li>When initial focus is to a Text field InstallOptions now follows standard Windows behaviour by
having the text selected</li>
<li>Label and other static fields no longer have State= written to the INI file when leaving the
dialog</li>
<li>NOTIFY flag can now be used with Link fields (State should be omitted in this case)</li>
<li>Likewise, State can now be used with Button fields (behaves the same as with Link fields)</li>
<li>NOTIFY flag can also now be used with ListBox and DropList fields to have NSIS notified when
the selection changes</li>
<li>Meaning of RIGHT flag is now reversed in right-to-left language mode</li>
<li>HSCROLL and VSCROLL flags are no longer restricted to Text fields</li>
<li>Various Link field fixes</li>
</ul>
</li>
</ul>
<ul>
<li>DLL version 2.3 (12/4/2003) <li>DLL version 2.3 (12/4/2003)
<ul> <ul>
<li>Added new control type "Button"</li> <li>Added new control type "Button"</li>
<li>Added new flag "NOTIFY"</li> <li>Added new flag "NOTIFY"</li>
<li>Added new flag "NOWORDWRAP" for multi-line text boxes</li> <li>Added new flag "NOWORDWRAP" for multi-line text boxes</li>
<li>Reduced size down to 12K</li> <li>Reduced size down to 12K</li>
<li>Better RTL support</li>
</ul> </ul>
</li> </li>
</ul> </ul>

View file

@ -1,5 +1,5 @@
[Settings] [Settings]
NumFields=4 NumFields=5
[Field 1] [Field 1]
Type=Label Type=Label
@ -34,3 +34,11 @@ Top=70
Bottom=80 Bottom=80
State=http://nsis.sourceforge.net/ State=http://nsis.sourceforge.net/
Text=* Homepage http://nsis.sourceforge.net/ Text=* Homepage http://nsis.sourceforge.net/
[Field 5]
Type=Text
Left=20
Right=-40
Top=85
Bottom=98
State=Just to test proper interaction with the other fields

View file

@ -1,5 +1,5 @@
[Settings] [Settings]
NumFields=9 NumFields=11
[Field 1] [Field 1]
Type=Groupbox Type=Groupbox
@ -31,6 +31,7 @@ Bottom=38
[Field 4] [Field 4]
Type=Checkbox Type=Checkbox
Text=Install support for Z Text=Install support for Z
Flags=RIGHT
State=0 State=0
Left=10 Left=10
Right=100 Right=100
@ -73,12 +74,32 @@ Right=-10
Top=97 Top=97
Bottom=118 Bottom=118
MinLen=1 MinLen=1
ValidateText=Please enter some text before proceeding.
[Field 9] [Field 9]
Type=Button Type=Button
Flags=NOTIFY Flags=NOTIFY
Text=Clear Text=&Clear
Left=-60 Left=-60
Right=-10 Right=-10
Top=27 Top=19
Bottom=41 Bottom=33
[Field 10]
Type=Button
Text=&Email
State=mailto:someone@anywhere.com
Left=-60
Right=-10
Top=35
Bottom=49
[Field 11]
Type=DROPLIST
ListItems=Show|Hide
State=Show
Flags=NOTIFY
Left=120
Right=-80
Top=20
Bottom=56

View file

@ -30,6 +30,8 @@ Page custom ShowCustom LeaveCustom ": Testing InstallOptions"
Function ShowCustom Function ShowCustom
; Initialise the dialog but don't show it yet ; Initialise the dialog but don't show it yet
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Test the right-to-left version?" IDNO +2
WriteINIStr "$PLUGINSDIR\test.ini" "Settings" "RTL" "1"
InstallOptions::initDialog /NOUNLOAD "$PLUGINSDIR\test.ini" InstallOptions::initDialog /NOUNLOAD "$PLUGINSDIR\test.ini"
; In this mode InstallOptions returns the window handle so we can use it ; In this mode InstallOptions returns the window handle so we can use it
Pop $hwnd Pop $hwnd
@ -45,9 +47,10 @@ Function LeaveCustom
; At this point the user has either pressed Next or one of our custom buttons ; At this point the user has either pressed Next or one of our custom buttons
; We find out which by reading from the INI file ; We find out which by reading from the INI file
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Settings" "State" ReadINIStr $0 "$PLUGINSDIR\test.ini" "Settings" "State"
StrCmp $0 0 validate ; Next button? StrCmp $0 0 validate ; Next button?
StrCmp $0 2 supportx ; "Install support for X"? StrCmp $0 2 supportx ; "Install support for X"?
StrCmp $0 9 clearbtn ; "Clear" button? StrCmp $0 9 clearbtn ; "Clear" button?
StrCmp $0 11 droplist ; "Show|Hide" drop-list?
Abort ; Return to the page Abort ; Return to the page
supportx: supportx:
@ -65,10 +68,23 @@ clearbtn:
SendMessage $1 ${WM_SETTEXT} 0 "STR:" SendMessage $1 ${WM_SETTEXT} 0 "STR:"
GetDlgItem $1 $hwnd 1206 ; DirRequest control (1200 + field 6 - 1 + 1 browse button) GetDlgItem $1 $hwnd 1206 ; DirRequest control (1200 + field 6 - 1 + 1 browse button)
SendMessage $1 ${WM_SETTEXT} 0 "STR:" SendMessage $1 ${WM_SETTEXT} 0 "STR:"
GetDlgItem $1 $hwnd 1209 ; DirRequest control (1200 + field 8 - 1 + 2 browse buttons) GetDlgItem $1 $hwnd 1209 ; Multiline control (1200 + field 8 - 1 + 2 browse buttons)
SendMessage $1 ${WM_SETTEXT} 0 "STR:" SendMessage $1 ${WM_SETTEXT} 0 "STR:"
Abort ; Return to the page Abort ; Return to the page
droplist:
; Make the DirRequest field depend on the droplist
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Field 11" "State"
StrCmp $0 "Show" +3
StrCpy $0 0
Goto +2
StrCpy $0 1
GetDlgItem $1 $hwnd 1206 ; DirRequest control (1200 + field 6 - 1 + 1 browse button)
EnableWindow $1 $0
GetDlgItem $1 $hwnd 1207 ; ... button (the following control)
EnableWindow $1 $0
Abort ; Return to the page
validate: validate:
; At this point we know the Next button was pressed, so perform any validation ; At this point we know the Next button was pressed, so perform any validation
ReadINIStr $0 "$PLUGINSDIR\test.ini" "Field 2" "State" ReadINIStr $0 "$PLUGINSDIR\test.ini" "Field 2" "State"

Binary file not shown.