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

@ -18,6 +18,15 @@
#include "../exdll/exdll.h"
#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 FREE(void *d) { if (d) GlobalFree((HGLOBAL)d); }
@ -62,57 +71,37 @@ char *WINAPI STRDUP(const char *c)
//---------------------------------------------------------------------
// settings
// crashes on windows 98 - #define IO_ENABLE_LINK
#define IO_ENABLE_LINK
//#define IO_LINK_UNDERLINED // Uncomment to show links text underlined
//---------------------------------------------------------------------
// general flags
#define FLAG_RIGHT 0x00000001
// Flags
// OFN_OVERWRITEPROMPT 0x00000002
// OFN_HIDEREADONLY 0x00000004
#define FLAG_DISABLED 0x00000008
#define FLAG_GROUP 0x00000010
#define FLAG_NOTABSTOP 0x00000020
// text box flags
#define FLAG_PASSWORD 0x00000040
#define FLAG_ONLYNUMBERS 0x00000080
#define FLAG_MULTILINE 0x00000100
// listbox flags
#define FLAG_MULTISELECT 0x00000200
#define FLAG_EXTENDEDSEL 0x00000400
// OFN_PATHMUSTEXIST 0x00000800
// OFN_FILEMUSTEXIST 0x00001000
// OFN_CREATEPROMPT 0x00002000
// combobox flags
#define FLAG_DROPLIST 0x00004000
// bitmap flags
#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
// LBS_NOTIFY 0x00000001 // LISTBOX/CHECKBOX/RADIOBUTTON/BUTTON/LINK - Notify NSIS script when control is "activated" (exact meaning depends on the type of control)
// OFN_OVERWRITEPROMPT 0x00000002 // FILEREQUEST
// OFN_HIDEREADONLY 0x00000004 // FILEREQUEST
// LBS_MULTIPLESEL 0x00000008 // LISTBOX
#define FLAG_READONLY 0x00000010 // TEXT/FILEREQUEST/DIRREQUEST
// BS_LEFTTEXT 0x00000020 // CHECKBOX/RADIOBUTTON
#define FLAG_PASSWORD 0x00000040 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_ONLYNUMBERS 0x00000080 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_MULTILINE 0x00000100 // TEXT/FILEREQUEST/DIRREQUEST
#define FLAG_NOWORDWRAP 0x00000200 // TEXT/FILEREQUEST/DIRREQUEST - Disable word-wrap in multi-line text boxes
#define FLAG_WANTRETURN 0x00000400 // TEXT/FILEREQUEST/DIRREQUEST
// LBS_EXTENDEDSEL 0x00000800 // LISTBOX
// OFN_PATHMUSTEXIST 0x00000800 // FILEREQUEST
// OFN_FILEMUSTEXIST 0x00001000 // FILEREQUEST
// OFN_CREATEPROMPT 0x00002000 // FILEREQUEST
#define FLAG_DROPLIST 0x00004000 // COMBOBOX
#define FLAG_RESIZETOFIT 0x00008000 // BITMAP
// WS_TABSTOP 0x00010000 // *ALL*
// WS_GROUP 0x00020000 // *ALL*
#define FLAG_SAVEAS 0x00040000 // FILEREQUEST - Show "Save As" instead of "Open" for FileRequest field
// OFN_EXPLORER 0x00080000 // FILEREQUEST
// WS_HSCROLL 0x00100000 // *ALL*
// WS_VSCROLL 0x00200000 // *ALL*
// WS_DISABLED 0x08000000 // *ALL*
struct TableEntry {
char *pszName;
@ -150,7 +139,7 @@ struct FieldType {
// initial buffer size. buffers will grow as required.
// 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[] = "...";
@ -159,7 +148,6 @@ HWND hMainWindow = NULL;
HWND hCancelButton = NULL;
HWND hNextButton = NULL;
HWND hBackButton = NULL;
HWND hInitialFocus = 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);
}
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) {
static TCHAR szDir[MAX_PATH];
static TCHAR szDir[MAX_PATH];
if (uMsg == BFFM_INITIALIZED) {
if (GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0) {
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
}
}
return 0;
if (uMsg == BFFM_INITIALIZED &&
GetWindowText(pFields[(int)pData].hwnd, szDir, MAX_PATH) > 0)
mySendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
return 0;
}
bool WINAPI ValidateFields() {
bool INLINE ValidateFields() {
int nIdx;
int nLength;
@ -228,7 +224,7 @@ bool WINAPI ValidateFields() {
if (pField->pszValidateText) {
MessageBox(hConfigWindow, pField->pszValidateText, NULL, MB_OK|MB_ICONWARNING);
}
SetFocus(pField->hwnd);
mySetFocus(pField->hwnd);
return false;
}
@ -239,110 +235,111 @@ bool WINAPI ValidateFields() {
bool WINAPI SaveSettings(void) {
static char szField[25];
int nIdx;
int nBufLen = MAX_BUFFER_LENGTH;
int nBufLen = BUFFER_SIZE;
char *pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
int CurrField = 1;
for (nIdx = 0; nIdx < nNumFields; nIdx++) {
int nIdx;
int CurrField;
for (nIdx = 0, CurrField = 1; nIdx < nNumFields; nIdx++, CurrField++) {
FieldType *pField = pFields + nIdx;
HWND hwnd = pField->hwnd;
switch (pField->nType) {
case FIELD_BROWSEBUTTON:
if (g_NotifyField > CurrField)
--g_NotifyField;
--CurrField;
default:
continue;
case FIELD_INVALID:
case FIELD_LABEL:
case FIELD_BUTTON:
*pszBuffer=0;
break;
case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON:
wsprintf(pszBuffer, "%d", !!mySendMessage(hwnd, BM_GETCHECK, 0, 0));
break;
case FIELD_LISTBOX:
{
// Ok, this one requires a bit of work.
// 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.
// 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.
int nLength = lstrlen(pField->pszListItems) + 10;
if (nLength > nBufLen) {
FREE(pszBuffer);
nBufLen = nLength;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
char *pszItem = (char*)MALLOC(nBufLen);
if (!pszItem) return false;
{
// Ok, this one requires a bit of work.
// 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.
// 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.
int nLength = lstrlen(pField->pszListItems) + 10;
if (nLength > nBufLen) {
FREE(pszBuffer);
nBufLen = nLength;
pszBuffer = (char*)MALLOC(nBufLen);
if (!pszBuffer) return false;
}
char *pszItem = (char*)MALLOC(nBufLen);
if (!pszItem) return false;
*pszBuffer = '\0';
int nNumItems = mySendMessage(hwnd, LB_GETCOUNT, 0, 0);
for (int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) {
if (mySendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) {
if (*pszBuffer) lstrcat(pszBuffer, "|");
mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)pszItem);
lstrcat(pszBuffer, pszItem);
*pszBuffer = '\0';
int nNumItems = mySendMessage(hwnd, LB_GETCOUNT, 0, 0);
for (int nIdx2 = 0; nIdx2 < nNumItems; nIdx2++) {
if (mySendMessage(hwnd, LB_GETSEL, nIdx2, 0) > 0) {
if (*pszBuffer) lstrcat(pszBuffer, "|");
mySendMessage(hwnd, LB_GETTEXT, (WPARAM)nIdx2, (LPARAM)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;
}
}
FREE(pszItem);
break;
}
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;
*p2 = 0;
nBufLen = nBufLen*2;
FREE(pszBuffer);
pszBuffer=pszBuf2;
}
break;
}
}
wsprintf(szField, "Field %d", CurrField);
WritePrivateProfileString(szField, "State", pszBuffer, pszFilename);
CurrField++;
}
// Tell NSIS which control was activated, if any
@ -356,7 +353,6 @@ bool WINAPI SaveSettings(void) {
#define BROWSE_WIDTH 15
#define BUFFER_SIZE 8192 // 8kb of mem is max char count in multiedit
static char szResult[BUFFER_SIZE];
DWORD WINAPI myGetProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName)
@ -432,59 +428,52 @@ int WINAPI ReadSettings(void) {
};
// Control flags
static TableEntry FlagTable[] = {
{ "RIGHT", FLAG_RIGHT },
{ "NOTIFY", LBS_NOTIFY },
{ "WARN_IF_EXIST", OFN_OVERWRITEPROMPT },
{ "FILE_HIDEREADONLY", OFN_HIDEREADONLY },
{ "DISABLED", FLAG_DISABLED },
{ "GROUP", FLAG_GROUP },
{ "NOTABSTOP", FLAG_NOTABSTOP },
{ "MULTISELECT", LBS_MULTIPLESEL },
{ "READONLY", FLAG_READONLY },
{ "RIGHT", BS_LEFTTEXT },
{ "PASSWORD", FLAG_PASSWORD },
{ "ONLY_NUMBERS", FLAG_ONLYNUMBERS },
{ "MULTILINE", FLAG_MULTILINE },
{ "MULTISELECT", FLAG_MULTISELECT },
{ "EXTENDEDSELCT", FLAG_EXTENDEDSEL },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST },
{ "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "WANTRETURN", FLAG_WANTRETURN },
{ "EXTENDEDSELCT", LBS_EXTENDEDSEL },
{ "PATH_MUST_EXIST", OFN_PATHMUSTEXIST },
{ "FILE_MUST_EXIST", OFN_FILEMUSTEXIST },
{ "PROMPT_CREATE", OFN_CREATEPROMPT },
{ "DROPLIST", FLAG_DROPLIST },
{ "RESIZETOFIT", FLAG_RESIZETOFIT },
{ "NOTIFY", FLAG_NOTIFY },
{ "NOTABSTOP", WS_TABSTOP },
{ "GROUP", WS_GROUP },
{ "REQ_SAVE", FLAG_SAVEAS },
{ "NOWORDWRAP", FLAG_NOWORDWRAP },
{ "FILE_EXPLORER", OFN_EXPLORER },
{ "WANTRETURN", FLAG_WANTRETURN },
{ "VSCROLL", FLAG_VSCROLL },
{ "HSCROLL", FLAG_HSCROLL },
{ "READONLY", FLAG_READONLY },
{ "HSCROLL", WS_HSCROLL },
{ "VSCROLL", WS_VSCROLL },
{ "DISABLED", WS_DISABLED },
{ NULL, 0 }
};
FieldType *pField = pFields + nIdx;
wsprintf(szField, "Field %d", nCtrlIdx + 1);
myGetProfileString(szField, "TYPE");
// Get the control type
myGetProfileString(szField, "TYPE");
pField->nType = LookupToken(TypeTable, szResult);
if (pField->nType == FIELD_INVALID)
continue;
// Lookup flags associated with the control type
pField->nFlags |= LookupToken(FlagTable, szResult);
pField->pszText = myGetProfileStringDup(szField, "TEXT");
// Label Text - convert newline
if (pField->nType == FIELD_LABEL) {
ConvertNewLines(pField->pszText);
}
pField->nFlags = LookupToken(FlagTable, szResult);
myGetProfileString(szField, "Flags");
pField->nFlags |= LookupTokens(FlagTable, szResult);
// pszState must not be NULL!
myGetProfileString(szField, "State");
pField->pszState = strdup(szResult);
pField->pszRoot = myGetProfileStringDup(szField, "ROOT");
// ListBox items list
{
int nResult = myGetProfileString(szField, "ListItems");
if (nResult) {
@ -495,21 +484,24 @@ int WINAPI ReadSettings(void) {
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
if (pField->pszValidateText) {
ConvertNewLines(pField->pszValidateText);
}
pField->pszValidateText = myGetProfileStringDup(szField, "ValidateText");
ConvertNewLines(pField->pszValidateText);
{
int nResult = GetPrivateProfileString(szField, "Filter", "All Files|*.*", szResult, sizeof(szResult), pszFilename);
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);
strcpy(pField->pszFilter, szResult);
char *pszPos = pField->pszFilter;
@ -521,15 +513,13 @@ int WINAPI ReadSettings(void) {
}
pField->rect.left = myGetProfileInt(szField, "LEFT", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.top = myGetProfileInt(szField, "TOP", 0);
pField->rect.right = myGetProfileInt(szField, "RIGHT", 0);
pField->rect.bottom = myGetProfileInt(szField, "BOTTOM", 0);
myGetProfileString(szField, "Flags");
pField->nFlags |= LookupTokens(FlagTable, szResult);
pField->nMinLength = myGetProfileInt(szField, "MinLen", 0);
pField->nMaxLength = myGetProfileInt(szField, "MaxLen", 0);
// 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->nControlID = 1200 + nIdx;
@ -538,7 +528,7 @@ int WINAPI ReadSettings(void) {
FieldType *pNewField = &pFields[nIdx+1];
pNewField->nControlID = 1200 + nIdx + 1;
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->rect.right = pField->rect.right;
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) {
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];
int nIdx = FindControlIdx(id);
@ -580,7 +572,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
tryagain:
if ((pField->nFlags & FLAG_SAVEAS) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) {
SetWindowText(pField->hwnd, szBrowsePath);
mySetWindowText(pField->hwnd, szBrowsePath);
break;
}
else if (szBrowsePath[0] && CommDlgExtendedError() == FNERR_INVALIDFILENAME) {
@ -625,7 +617,7 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
break;
if (SHGetPathFromIDList(pResult, szBrowsePath)) {
SetWindowText(pField->hwnd, szBrowsePath);
mySetWindowText(pField->hwnd, szBrowsePath);
}
LPMALLOC pMalloc;
@ -637,16 +629,20 @@ LRESULT WINAPI WMCommandProc(HWND hWnd, UINT id, HWND hwndCtl, UINT codeNotify)
}
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;
}
if (pField->nFlags & FLAG_NOTIFY) {
if (pField->nFlags & LBS_NOTIFY) {
// Remember which control was activated then pretend the user clicked Next
g_NotifyField = nIdx + 1;
// the next button must be enabled or nsis will ignore WM_COMMAND
BOOL bWasDisabled = EnableWindow(hNextButton, TRUE);
FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, codeNotify, mySendMessage);
FORWARD_WM_COMMAND(hMainWindow, IDOK, hNextButton, BN_CLICKED, mySendMessage);
if (bWasDisabled)
EnableWindow(hNextButton, FALSE);
}
@ -715,13 +711,12 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
// We need lpdis->rcItem later
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
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
if (bRTL)
{
@ -729,19 +724,24 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
rc.right += lpdis->rcItem.right - rc.right;
}
// Make some more room so the focus rect won't cut letters off
rc.right = min(rc.right + 2, lpdis->rcItem.right);
if (lpdis->itemAction & ODA_DRAWENTIRE)
{
// 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
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0));
// Draw the text
DrawText(lpdis->hDC, pField->pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | (bRTL ? DT_RTLREADING : 0));
}
// 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);
}
MapWindowPoints(lpdis->hwndItem, 0, (LPPOINT) &rc, 2);
pField->rect = rc;
#ifdef IO_LINK_UNDERLINED
@ -755,7 +755,7 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_CTLCOLORBTN:
case WM_CTLCOLORLISTBOX:
// let the NSIS window handle colors, it knows best
return mySendMessage(hMainWindow, WM_CTLCOLORSTATIC, wParam, lParam);
return mySendMessage(hMainWindow, uMsg, wParam, lParam);
}
return 0;
}
@ -766,31 +766,44 @@ BOOL CALLBACK cfgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
#ifndef BS_TYPEMASK
#define BS_TYPEMASK 0x0000000FL
#endif
// pFields[nIdx].nParentIdx is used to store original windowproc
int WINAPI StaticLINKWindowProc(HWND hWin, UINT uMsg, LPARAM wParam, WPARAM lParam)
{
int CtrlId = GetDlgCtrlID(hWin);
int StaticField = FindControlIdx(CtrlId);
int StaticField = FindControlIdx(GetDlgCtrlID(hWin));
if (StaticField < 0)
return 0;
FieldType *pField = pFields + StaticField;
switch(uMsg)
{
case WM_SETFOCUS:
mySendMessage(hConfigWindow, DM_SETDEFID, CtrlId, 0);
// remove the BS_DEFPUSHBUTTON style from IDOK
mySendMessage(GetDlgItem(hMainWindow, IDOK), BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
break;
case WM_NCHITTEST:
case WM_GETDLGCODE:
// Pretend we are a normal button/default button as appropriate
return DLGC_BUTTON | ((pField->nFlags & FLAG_WANTRETURN) ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
case BM_SETSTYLE:
// 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)};
MapWindowPoints(0, hWin, &pt, 1);
if (PtInRect(&pField->rect, pt))
return HTCLIENT;
else
return HTNOWHERE;
}
case WM_SETCURSOR:
case WM_SETCURSOR:
{
if ((HWND)wParam == hWin && LOWORD(lParam) == HTCLIENT)
{
@ -838,12 +851,12 @@ int WINAPI createCfgDlg()
}
hCancelButton = GetDlgItem(mainwnd,IDCANCEL);
hInitialFocus = hNextButton = GetDlgItem(mainwnd,IDOK);
hNextButton = GetDlgItem(mainwnd,IDOK);
hBackButton = GetDlgItem(mainwnd,3);
if (pszCancelButtonText) SetWindowText(hCancelButton,pszCancelButtonText);
if (pszNextButtonText) SetWindowText(hNextButton,pszNextButtonText);
if (pszBackButtonText) SetWindowText(hBackButton,pszBackButtonText);
mySetWindowText(hCancelButton,pszCancelButtonText);
mySetWindowText(hNextButton,pszNextButtonText);
mySetWindowText(hBackButton,pszBackButtonText);
if (bBackEnabled!=-1) EnableWindow(hBackButton,bBackEnabled);
if (bCancelEnabled!=-1) EnableWindow(hCancelButton,bCancelEnabled);
@ -894,6 +907,8 @@ int WINAPI createCfgDlg()
DeleteDC(memDC);
BOOL fFocused = FALSE;
#define DEFAULT_STYLES (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
for (int nIdx = 0; nIdx < nNumFields; nIdx++) {
@ -905,18 +920,18 @@ int WINAPI createCfgDlg()
DWORD dwRTLExStyle;
} ClassTable[] = {
{ "STATIC", // FIELD_LABEL
DEFAULT_STYLES /*| WS_TABSTOP*/,
DEFAULT_STYLES | SS_RIGHT /*| WS_TABSTOP*/,
DEFAULT_STYLES,
DEFAULT_STYLES | SS_RIGHT,
WS_EX_TRANSPARENT,
WS_EX_TRANSPARENT | WS_EX_RTLREADING },
{ "STATIC", // FIELD_ICON
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_ICON,
DEFAULT_STYLES | SS_ICON,
DEFAULT_STYLES | SS_ICON,
0,
WS_EX_RTLREADING },
{ "STATIC", // FIELD_BITMAP
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES /*| WS_TABSTOP*/ | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
DEFAULT_STYLES | SS_BITMAP | SS_CENTERIMAGE,
0,
WS_EX_RTLREADING },
{ "BUTTON", // FIELD_BROWSEBUTTON
@ -1025,9 +1040,7 @@ int WINAPI createCfgDlg()
break;
case FIELD_CHECKBOX:
case FIELD_RADIOBUTTON:
case FIELD_BUTTON:
if (pField->nFlags & FLAG_RIGHT)
dwStyle |= BS_RIGHTBUTTON;
dwStyle ^= pField->nFlags & BS_LEFTTEXT;
break;
case FIELD_TEXT:
case FIELD_FILEREQUEST:
@ -1036,40 +1049,37 @@ int WINAPI createCfgDlg()
dwStyle |= ES_PASSWORD;
if (pField->nFlags & FLAG_ONLYNUMBERS)
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)
{
dwStyle |= ES_MULTILINE | ES_AUTOVSCROLL;
// Enable word-wrap unless we have a horizontal scroll bar
// or it has been explicitly disallowed
if (!(pField->nFlags & (FLAG_HSCROLL | FLAG_NOWORDWRAP)))
if (!(pField->nFlags & (WS_HSCROLL | FLAG_NOWORDWRAP)))
dwStyle &= ~ES_AUTOHSCROLL;
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;
case FIELD_COMBOBOX:
dwStyle |= (pField->nFlags & FLAG_DROPLIST) ? CBS_DROPDOWNLIST : CBS_DROPDOWN;
title = pField->pszState;
break;
case FIELD_LISTBOX:
if (pField->nFlags & FLAG_EXTENDEDSEL)
dwStyle |= LBS_EXTENDEDSEL;
if (pField->nFlags & FLAG_MULTISELECT)
dwStyle |= LBS_MULTIPLESEL;
dwStyle |= pField->nFlags & (LBS_NOTIFY | LBS_MULTIPLESEL | LBS_EXTENDEDSEL);
break;
}
if (pField->nFlags & FLAG_DISABLED) dwStyle |= WS_DISABLED;
if (pField->nFlags & FLAG_GROUP) dwStyle |= WS_GROUP;
if (pField->nFlags & FLAG_NOTABSTOP) dwStyle &= ~WS_TABSTOP;
dwStyle |= pField->nFlags & (WS_GROUP | WS_HSCROLL | WS_VSCROLL | WS_DISABLED);
if (pField->nFlags & WS_TABSTOP) dwStyle &= ~WS_TABSTOP;
HWND hwCtrl = pField->hwnd = CreateWindowEx(
dwExStyle,
@ -1090,15 +1100,20 @@ int WINAPI createCfgDlg()
// Sets the font of IO window to be the same as the main window
mySendMessage(hwCtrl, WM_SETFONT, (WPARAM)hFont, TRUE);
// Set initial focus to the first appropriate field
if ((hInitialFocus == hNextButton) && (dwStyle & WS_TABSTOP))
hInitialFocus = hwCtrl;
if (!fFocused && (dwStyle & (WS_TABSTOP | WS_DISABLED)) == WS_TABSTOP) {
fFocused = TRUE;
mySetFocus(hwCtrl);
}
// make sure we created the window, then set additional attributes
switch (pField->nType) {
case FIELD_TEXT:
mySendMessage(hwCtrl, WM_SETTEXT, 0, (LPARAM)title);
// no break;
case FIELD_FILEREQUEST:
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);
break;
@ -1139,7 +1154,7 @@ int WINAPI createCfgDlg()
}
FREE(pszList);
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);
pszStart = pszEnd = pField->pszState;
while (*pszStart) {
@ -1212,8 +1227,10 @@ int WINAPI createCfgDlg()
}
}
if (pszTitle)
SetWindowText(mainwnd,pszTitle);
if (!fFocused)
mySetFocus(hNextButton);
mySetWindowText(mainwnd,pszTitle);
pFilenameStackEntry = *g_stacktop;
*g_stacktop = (*g_stacktop)->next;
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
mySendMessage(hMainWindow, WM_NOTIFY_CUSTOM_READY, (WPARAM)hConfigWindow, 0);
ShowWindow(hConfigWindow, SW_SHOWNA);
SetFocus(hInitialFocus);
g_done = g_NotifyField = 0;
@ -1364,15 +1380,15 @@ void WINAPI ConvertNewLines(char *str) {
for (p1=p2=str; *p1; p1++, p2++) {
if (*p1 == '\\') {
switch (p1[1]) {
case 't':
*p2 = '\t';
break;
case 'n':
*p2 = '\n';
break;
case 'r':
*p2 = '\r';
break;
case 't':
*p2 = '\t';
break;
case '\\':
*p2 = '\\';
break;