2228 lines
64 KiB
C++
2228 lines
64 KiB
C++
|
#include <windows.h>
|
||
|
#ifdef UNICODE
|
||
|
#include "nsis_unicode/pluginapi.h"
|
||
|
#else
|
||
|
#include "nsis_ansi/pluginapi.h"
|
||
|
#endif
|
||
|
#include "resource.h"
|
||
|
#include <commctrl.h>
|
||
|
|
||
|
/**
|
||
|
EmbeddedLists v1.4 RC2 by Afrow UK
|
||
|
A plugin dll for NSIS that shows list controls.
|
||
|
See Docs\EmbeddedLists\Readme.txt
|
||
|
|
||
|
Last modified: 8th July 2010
|
||
|
*/
|
||
|
|
||
|
#define TEXT_CHECKALL TEXT("Check all")
|
||
|
#define TEXT_UNCHECKALL TEXT("Uncheck all")
|
||
|
#define TEXT_SELECTALL TEXT("Select all")
|
||
|
#define TEXT_UNSELECTALL TEXT("Unselect all")
|
||
|
|
||
|
// Common keys.
|
||
|
#define KEY_TEXT TEXT("Text")
|
||
|
|
||
|
// Settings.
|
||
|
#define SEC_SETTINGS TEXT("Settings")
|
||
|
#define KEY_TYPE TEXT("Type") // ListView|TreeView
|
||
|
#define KEY_HEADINGTEXT TEXT("HeadingText")
|
||
|
#define KEY_GROUPTEXT TEXT("GroupText")
|
||
|
#define KEY_CAPTION TEXT("Caption")
|
||
|
#define KEY_NEXTTOGGLE TEXT("ToggleNextButton") // 0|1
|
||
|
#define KEY_CHECKBOXES TEXT("CheckBoxes")
|
||
|
#define KEY_SORT TEXT("Sort") // none|ascending|descending
|
||
|
#define KEY_SORTBYCOLUMNCLICK TEXT("SortByColumnClick") // 0|1
|
||
|
#define KEY_SORTBYCOLUMN TEXT("SortByColumn")
|
||
|
#define KEY_COLHEADER TEXT("ColumnHeader") // 0|1
|
||
|
#define KEY_SINGLESELECT TEXT("SingleSelect") // 0|1
|
||
|
#define KEY_LABELEDIT TEXT("LabelEdit") // 0|1
|
||
|
#define KEY_NOITEMSELECT TEXT("NoItemSelection") // 0|1
|
||
|
#define KEY_PARENTCHECK TEXT("ParentCheck") // 0|1
|
||
|
#define KEY_RECT TEXT("Rect")
|
||
|
#define KEY_VIEWCONTROLONLY TEXT("ViewListOnly") // 0|1
|
||
|
#define KEY_RETURNITEMTEXT TEXT("ReturnItemText") // 0|1
|
||
|
#define KEY_USECHECKBITMAP TEXT("UseCheckBitmap") // 0|1
|
||
|
|
||
|
// Icon lists.
|
||
|
#define SEC_ICONLIST TEXT("Icons")
|
||
|
#define KEY_ICONCOUNT TEXT("IconCount")
|
||
|
#define KEY_ICONFILE TEXT("Icon") // Icon#=
|
||
|
|
||
|
// ListView Columns.
|
||
|
#define SEC_COLUMNS TEXT("Columns")
|
||
|
#define KEY_COLUMN TEXT("Column")
|
||
|
#define KEY_WIDTH TEXT("Width")
|
||
|
|
||
|
// Items/Nodes.
|
||
|
#define SEC_ITEM TEXT("Item")
|
||
|
#define KEY_SUBITEM TEXT("SubItem") // SubItem#=
|
||
|
#define KEY_ICONINDEX TEXT("IconIndex")
|
||
|
#define KEY_SELECTED TEXT("Selected") // 0|1
|
||
|
#define KEY_CHECKED TEXT("Checked") // 0|1
|
||
|
#define KEY_POSITION TEXT("Position")
|
||
|
#define KEY_EXPANDED TEXT("Expanded") // 0|1
|
||
|
#define KEY_BOLDTEXT TEXT("BoldText") // 0|1
|
||
|
#define KEY_DISABLECHECK TEXT("DisableCheck") // 0|1|2
|
||
|
#define KEY_DISABLEEDIT TEXT("DisableLabelEdit") // 0|1
|
||
|
// Uses KEY_TEXT
|
||
|
|
||
|
#define DEFAULT_RECT 1018
|
||
|
|
||
|
// Nothing selected return value.
|
||
|
#define OUT_ERROR TEXT("ERROR")
|
||
|
#define OUT_NEXT TEXT("NEXT")
|
||
|
#define OUT_BACK TEXT("BACK")
|
||
|
#define OUT_CANCEL TEXT("CANCEL")
|
||
|
#define OUT_ENDSTACK TEXT("/END")
|
||
|
|
||
|
#define DLG_LISTVIEW TEXT("ListView")
|
||
|
#define DLG_TREEVIEW TEXT("TreeView")
|
||
|
|
||
|
#define LVIS_UNCHECKED INDEXTOSTATEIMAGEMASK(1)
|
||
|
#define LVIS_CHECKED INDEXTOSTATEIMAGEMASK(2)
|
||
|
#define TVIS_UNCHECKED INDEXTOSTATEIMAGEMASK(1)
|
||
|
#define TVIS_CHECKED INDEXTOSTATEIMAGEMASK(2)
|
||
|
|
||
|
#define LVIS_IMAGE_BLANK INDEXTOSTATEIMAGEMASK(0)
|
||
|
#define LVIS_IMAGE_UNCHECKED INDEXTOSTATEIMAGEMASK(2)
|
||
|
#define LVIS_IMAGE_CHECKED INDEXTOSTATEIMAGEMASK(3)
|
||
|
#define LVIS_IMAGE_PCHECKED INDEXTOSTATEIMAGEMASK(4)
|
||
|
#define LVIS_IMAGE_DISUNCHECKED INDEXTOSTATEIMAGEMASK(5)
|
||
|
#define LVIS_IMAGE_DISCHECKED INDEXTOSTATEIMAGEMASK(6)
|
||
|
|
||
|
#define TVIS_IMAGE_BLANK INDEXTOSTATEIMAGEMASK(0)
|
||
|
#define TVIS_IMAGE_UNCHECKED INDEXTOSTATEIMAGEMASK(1)
|
||
|
#define TVIS_IMAGE_CHECKED INDEXTOSTATEIMAGEMASK(2)
|
||
|
#define TVIS_IMAGE_PCHECKED INDEXTOSTATEIMAGEMASK(3)
|
||
|
#define TVIS_IMAGE_DISUNCHECKED INDEXTOSTATEIMAGEMASK(4)
|
||
|
#define TVIS_IMAGE_DISCHECKED INDEXTOSTATEIMAGEMASK(5)
|
||
|
|
||
|
#ifndef GetWindowLongPtr
|
||
|
#define GetWindowLongPtr GetWindowLong
|
||
|
#endif
|
||
|
|
||
|
#ifndef SetWindowLongPtr
|
||
|
#define SetWindowLongPtr SetWindowLong
|
||
|
#endif
|
||
|
|
||
|
#ifndef GWLP_WNDPROC
|
||
|
#define GWLP_WNDPROC GWL_WNDPROC
|
||
|
#endif
|
||
|
|
||
|
#ifndef DWLP_DLGPROC
|
||
|
#define DWLP_DLGPROC DWL_DLGPROC
|
||
|
#endif
|
||
|
|
||
|
#ifndef LVM_SORTITEMSEX
|
||
|
#define LVM_SORTITEMSEX (LVM_FIRST + 81)
|
||
|
#endif
|
||
|
|
||
|
#ifndef ListView_SortItemsEx
|
||
|
#define ListView_SortItemsEx(hwndLV, _pfnCompare, _lPrm) \
|
||
|
(BOOL)SendMessage((hwndLV), LVM_SORTITEMSEX, (WPARAM)(LPARAM)(_lPrm), (LPARAM)(PFNLVCOMPARE)(_pfnCompare))
|
||
|
#endif
|
||
|
|
||
|
#ifndef LVS_EX_LABELTIP
|
||
|
#define LVS_EX_LABELTIP 0x00004000
|
||
|
#endif
|
||
|
|
||
|
#define ReadINIStr(ReturnStr,Section,Key,DefaultVal) \
|
||
|
GetPrivateProfileString(Section,Key,DefaultVal,ReturnStr,g_stringsize,g_szINIFilePath)
|
||
|
|
||
|
#define ReadINIInt(ReturnInt,Section,Key,DefaultVal) \
|
||
|
(ReturnInt = GetPrivateProfileInt(Section,Key,DefaultVal,g_szINIFilePath))
|
||
|
|
||
|
#define WriteINIStr(Section,Key,Val) \
|
||
|
WritePrivateProfileString(Section,Key,Val,g_szINIFilePath)
|
||
|
|
||
|
#ifndef GET_X_LPARAM
|
||
|
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
||
|
#endif
|
||
|
|
||
|
#ifndef GET_Y_LPARAM
|
||
|
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
||
|
#endif
|
||
|
|
||
|
HINSTANCE g_hInstance;
|
||
|
HWND g_hWndParent;
|
||
|
HWND g_hDialog;
|
||
|
HWND g_hCtl;
|
||
|
|
||
|
TCHAR g_szINIFilePath[MAX_PATH];
|
||
|
|
||
|
WNDPROC ParentDlgProcOld;
|
||
|
|
||
|
BOOL g_done = FALSE, g_is_cancel = FALSE, g_is_back = FALSE, g_bInitDialog = FALSE;
|
||
|
|
||
|
/* Check boxes or not?
|
||
|
0 = no
|
||
|
1 = yes
|
||
|
2 = partialy checked supported*/
|
||
|
int g_iCheckBoxes = FALSE;
|
||
|
// Allow label editing?
|
||
|
BOOL g_bLabelEdit = FALSE;
|
||
|
BOOL g_bParentCheck = FALSE;
|
||
|
// Allow item selection?
|
||
|
BOOL g_bNoItemSelect = FALSE;
|
||
|
// Only display tree view / list view control on dialog.
|
||
|
BOOL g_bViewControlOnly = FALSE;
|
||
|
// Return the item text rather than the item number.
|
||
|
BOOL g_bReturnItemText = FALSE;
|
||
|
// Which dialog...
|
||
|
int g_iDialog = 0;
|
||
|
/* 0 = list view
|
||
|
1 = tree view
|
||
|
*/
|
||
|
long g_iListItemCount = 0;
|
||
|
|
||
|
// Stores info for item sorting.
|
||
|
struct SORTBY
|
||
|
{
|
||
|
int iColumn; // Column number (1 based).
|
||
|
int iSort; // 0 = ascending, 1 = descending.
|
||
|
};
|
||
|
typedef SORTBY* PSORTBY;
|
||
|
|
||
|
// Stores old item information.
|
||
|
struct OLDITEM
|
||
|
{
|
||
|
int iChecked; // 0 = unchecked, 1 = checked, 2 = partially unchecked, 3 = partially checked
|
||
|
int iDisableCheck; // 0 = no disable, 2 = disabled, 3 = hidden
|
||
|
BOOL bDisableEdit;
|
||
|
int iOldIndex;
|
||
|
PTCHAR pszOldText;
|
||
|
};
|
||
|
typedef OLDITEM* POLDITEM;
|
||
|
|
||
|
BOOL CALLBACK ListView_ParentDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
BOOL CALLBACK TreeView_ParentDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
#define NSISFUNC(name) extern "C" void __declspec(dllexport) name(HWND hWndParent, int string_size, PTCHAR variables, stack_t** stacktop, extra_parameters* extra)
|
||
|
BOOL g_bInited;
|
||
|
#define DLL_INIT() \
|
||
|
{ \
|
||
|
if (!g_bInited) \
|
||
|
{ \
|
||
|
g_hWndParent = hWndParent; \
|
||
|
EXDLL_INIT(); \
|
||
|
extra->RegisterPluginCallback(g_hInstance, PluginCallback); \
|
||
|
g_bInited = TRUE; \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
// Creates an OLDITEM.
|
||
|
POLDITEM CreateOldItem(int iSectionCount, PTCHAR pszSectionName, PTCHAR pszValue)
|
||
|
{
|
||
|
int iValue;
|
||
|
POLDITEM poi = (POLDITEM)GlobalAlloc(GPTR, sizeof(OLDITEM));
|
||
|
{
|
||
|
// Store original item info.
|
||
|
poi->iOldIndex = iSectionCount;
|
||
|
poi->pszOldText = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR)*(lstrlen(pszValue)+1));
|
||
|
lstrcpy(poi->pszOldText, pszValue);
|
||
|
|
||
|
if (g_iCheckBoxes)
|
||
|
{
|
||
|
// Is this item checked.
|
||
|
if (ReadINIInt(iValue, pszSectionName, KEY_CHECKED, 0))
|
||
|
poi->iChecked = TRUE;
|
||
|
else
|
||
|
poi->iChecked = FALSE;
|
||
|
|
||
|
// Is this item check state changable?
|
||
|
if (ReadINIInt(iValue, pszSectionName, KEY_DISABLECHECK, 0) != 0)
|
||
|
{
|
||
|
if (iValue == 2)
|
||
|
poi->iDisableCheck = 2;
|
||
|
else
|
||
|
poi->iDisableCheck = TRUE;
|
||
|
}
|
||
|
else
|
||
|
poi->iDisableCheck = FALSE;
|
||
|
}
|
||
|
|
||
|
// Is this item label editable?
|
||
|
if (ReadINIInt(iValue, pszSectionName, KEY_DISABLEEDIT, 0) != 0)
|
||
|
poi->bDisableEdit = TRUE;
|
||
|
}
|
||
|
|
||
|
return poi;
|
||
|
}
|
||
|
|
||
|
// Sets common control texts.
|
||
|
void SetCommonTexts(HWND hWndDlg)
|
||
|
{
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
|
||
|
// Get heading label text.
|
||
|
ReadINIStr(pszValue, SEC_SETTINGS, KEY_HEADINGTEXT, TEXT(""));
|
||
|
SetWindowText(GetDlgItem(hWndDlg, IDC_HEADINGTEXT), pszValue);
|
||
|
|
||
|
// Get group box label text.
|
||
|
ReadINIStr(pszValue, SEC_SETTINGS, KEY_GROUPTEXT, TEXT(""));
|
||
|
SetWindowText(GetDlgItem(hWndDlg, IDC_GROUPBOX), pszValue);
|
||
|
|
||
|
// Set dialog caption.
|
||
|
if (ReadINIStr(pszValue, SEC_SETTINGS, KEY_CAPTION, TEXT("")))
|
||
|
SetWindowText(g_hWndParent, pszValue);
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
}
|
||
|
|
||
|
// Displays our dialog.
|
||
|
void ShowDialog()
|
||
|
{
|
||
|
if (g_hDialog)
|
||
|
{
|
||
|
HWND hRect;
|
||
|
RECT dialog_r;
|
||
|
int mainWndWidth, mainWndHeight;
|
||
|
int iRect;
|
||
|
|
||
|
// Set dialog font to that of the parent window font.
|
||
|
SendMessage(g_hDialog, WM_SETFONT, (WPARAM)SendMessage(g_hWndParent, WM_GETFONT, 0, 0), TRUE);
|
||
|
|
||
|
// Get which rect to place our dialog on.
|
||
|
ReadINIInt(iRect, SEC_SETTINGS, KEY_RECT, DEFAULT_RECT);
|
||
|
hRect = GetDlgItem(g_hWndParent, iRect);
|
||
|
|
||
|
// Check rect exists.
|
||
|
if (!hRect)
|
||
|
{
|
||
|
pushstring(OUT_ERROR);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the sizes of the UI.
|
||
|
GetWindowRect(hRect, &dialog_r);
|
||
|
MapWindowPoints(0, g_hWndParent, (LPPOINT)&dialog_r, 2);
|
||
|
|
||
|
mainWndWidth = dialog_r.right - dialog_r.left;
|
||
|
mainWndHeight = dialog_r.bottom - dialog_r.top;
|
||
|
|
||
|
// Set our window size to fit the UI size.
|
||
|
iRect = MoveWindow(
|
||
|
g_hDialog,
|
||
|
dialog_r.left,
|
||
|
dialog_r.top,
|
||
|
mainWndWidth,
|
||
|
mainWndHeight,
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
// Do we only want to display the list / tree view in dialog?
|
||
|
if (ReadINIInt(iRect, SEC_SETTINGS, KEY_VIEWCONTROLONLY, 0) == 1)
|
||
|
{
|
||
|
// Remove unwanted controls.
|
||
|
DestroyWindow(GetDlgItem(g_hDialog, IDC_HEADINGTEXT));
|
||
|
DestroyWindow(GetDlgItem(g_hDialog, IDC_GROUPBOX));
|
||
|
|
||
|
// Set our window size to fit the UI size.
|
||
|
MoveWindow(
|
||
|
g_hCtl,
|
||
|
0,
|
||
|
0,
|
||
|
mainWndWidth,
|
||
|
mainWndHeight,
|
||
|
FALSE
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HWND hCtl;
|
||
|
int iTop;
|
||
|
|
||
|
// Get the size of the heading label.
|
||
|
hCtl = GetDlgItem(g_hDialog, IDC_HEADINGTEXT);
|
||
|
GetWindowRect(hCtl, &dialog_r);
|
||
|
iTop = dialog_r.bottom - dialog_r.top;
|
||
|
|
||
|
// Resize heading label.
|
||
|
MoveWindow(
|
||
|
hCtl,
|
||
|
0,
|
||
|
0,
|
||
|
mainWndWidth,
|
||
|
iTop,
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
// Get the size of the group box.
|
||
|
hCtl = GetDlgItem(g_hDialog, IDC_GROUPBOX);
|
||
|
|
||
|
// Resize group box.
|
||
|
MoveWindow(
|
||
|
hCtl,
|
||
|
0,
|
||
|
iTop,
|
||
|
mainWndWidth,
|
||
|
mainWndHeight - iTop - 5,
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
iTop += 15;
|
||
|
|
||
|
// Resize list view / tree view.
|
||
|
MoveWindow(
|
||
|
g_hCtl,
|
||
|
8,
|
||
|
iTop,
|
||
|
mainWndWidth - 15,
|
||
|
mainWndHeight - iTop - 15,
|
||
|
FALSE
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
// Sub-class parent window procedure.
|
||
|
if (g_iDialog == 0)
|
||
|
// For list view dialog.
|
||
|
ParentDlgProcOld = (WNDPROC)SetWindowLongPtr(g_hWndParent, DWLP_DLGPROC, (LONG)ListView_ParentDlgProc);
|
||
|
else
|
||
|
// For tree view dialog.
|
||
|
ParentDlgProcOld = (WNDPROC)SetWindowLongPtr(g_hWndParent, DWLP_DLGPROC, (LONG)TreeView_ParentDlgProc);
|
||
|
|
||
|
// Sets the font of IO window to be the same as the main window.
|
||
|
SendMessage(g_hDialog, WM_SETFONT, (WPARAM)SendMessage(g_hWndParent, WM_GETFONT, 0, 0), (LPARAM)TRUE);
|
||
|
|
||
|
// Tell NSIS to remove old inner dialog and pass handle of the new inner dialog.
|
||
|
SendMessage(g_hWndParent, WM_NOTIFY_CUSTOM_READY, (WPARAM)g_hDialog, 0);
|
||
|
ShowWindow(g_hDialog, SW_SHOW);
|
||
|
|
||
|
g_done = FALSE;
|
||
|
|
||
|
// Loop until the user clicks on a button.
|
||
|
while (!g_done) {
|
||
|
MSG msg;
|
||
|
int nResult = GetMessage(&msg, NULL, 0, 0);
|
||
|
if (!IsDialogMessage(g_hDialog, &msg) && !IsDialogMessage(g_hWndParent, &msg))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set window dialog procedure back to NSIS's.
|
||
|
SetWindowLongPtr(g_hWndParent, DWL_DLGPROC, (long)ParentDlgProcOld);
|
||
|
DestroyWindow(g_hDialog);
|
||
|
|
||
|
// Return page button result.
|
||
|
pushstring(g_is_cancel ? OUT_CANCEL : g_is_back ? OUT_BACK : OUT_NEXT);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
pushstring(OUT_ERROR);
|
||
|
}
|
||
|
|
||
|
// Get icons from icon list in INI file.
|
||
|
HIMAGELIST GetIcons()
|
||
|
{
|
||
|
static TCHAR szSectionName[32], szIconPath[MAX_PATH];
|
||
|
int iIcons, iSectionCount;
|
||
|
HICON hIcon;
|
||
|
HIMAGELIST himlIcons = NULL;
|
||
|
wsprintf(szSectionName, TEXT("%s%i"), KEY_ICONFILE, iSectionCount = 1);
|
||
|
while (ReadINIStr(szIconPath, SEC_ICONLIST, szSectionName, TEXT("")))
|
||
|
{
|
||
|
if (!himlIcons)
|
||
|
himlIcons = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, ReadINIInt(iIcons, SEC_ICONLIST, KEY_ICONCOUNT, 8), 0);
|
||
|
|
||
|
hIcon = (HICON)LoadImage(g_hInstance, szIconPath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE | LR_LOADTRANSPARENT | LR_SHARED);
|
||
|
if (hIcon)
|
||
|
ImageList_AddIcon(himlIcons, hIcon);
|
||
|
DestroyIcon(hIcon);
|
||
|
|
||
|
wsprintf(szSectionName, TEXT("%s%i"), KEY_ICONFILE, ++iSectionCount);
|
||
|
}
|
||
|
return himlIcons;
|
||
|
}
|
||
|
|
||
|
// Get check state image from installer exe header.
|
||
|
HIMAGELIST GetStateImage(PTCHAR pszPath)
|
||
|
{
|
||
|
HBITMAP hStateImage;
|
||
|
HIMAGELIST himlState;
|
||
|
|
||
|
if (lstrcmp(pszPath, TEXT("1")) == 0)
|
||
|
hStateImage = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP), IMAGE_BITMAP, 96, 16, LR_SHARED);
|
||
|
else
|
||
|
hStateImage = (HBITMAP)LoadImage(g_hInstance, pszPath, IMAGE_BITMAP, 96, 16, LR_LOADFROMFILE | LR_SHARED);
|
||
|
|
||
|
if (!hStateImage)
|
||
|
return NULL;
|
||
|
|
||
|
himlState = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 6, 0);
|
||
|
ImageList_AddMasked(himlState, hStateImage, RGB(255, 0, 255));
|
||
|
|
||
|
DeleteObject(hStateImage);
|
||
|
|
||
|
g_iCheckBoxes = 2;
|
||
|
return himlState;
|
||
|
}
|
||
|
|
||
|
// Frees memory allocated for each list view item.
|
||
|
void ListView_FreeParams()
|
||
|
{
|
||
|
static LVITEM lvi;
|
||
|
static POLDITEM poi;
|
||
|
lvi.mask = TVIF_PARAM;
|
||
|
lvi.iItem = 0;
|
||
|
// Get lParam.
|
||
|
while (ListView_GetItem(g_hCtl, &lvi))
|
||
|
{
|
||
|
// Get OLDITEM data.
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
|
||
|
// Free memory allocated.
|
||
|
GlobalFree(poi->pszOldText);
|
||
|
GlobalFree(poi);
|
||
|
|
||
|
// Next item.
|
||
|
lvi.iItem += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get number of checked items.
|
||
|
BOOL ListView_IsItemChecked()
|
||
|
{
|
||
|
LVITEM lvi;
|
||
|
for (int i=0; i<ListView_GetItemCount(g_hCtl); i++)
|
||
|
{
|
||
|
lvi.mask = LVIF_PARAM;
|
||
|
lvi.iItem = i;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
if (((POLDITEM)lvi.lParam)->iChecked == TRUE)
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Compare items in list view.
|
||
|
static int CALLBACK ListView_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
||
|
{
|
||
|
static PSORTBY psb;
|
||
|
static LVITEM lvi;
|
||
|
PTCHAR pszText1 = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
PTCHAR pszText2 = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
|
||
|
psb = (PSORTBY)lParamSort;
|
||
|
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iSubItem = psb->iColumn-1;
|
||
|
|
||
|
lvi.iItem = lParam1;
|
||
|
lvi.pszText = pszText1;
|
||
|
lvi.cchTextMax = g_stringsize;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
lvi.iItem = lParam2;
|
||
|
lvi.pszText = pszText2;
|
||
|
lvi.cchTextMax = g_stringsize;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
int result;
|
||
|
if (psb->iSort == 0)
|
||
|
result = lstrcmpi(pszText1, pszText2);
|
||
|
else
|
||
|
result = lstrcmpi(pszText2, pszText1);
|
||
|
|
||
|
LocalFree(pszText1);
|
||
|
LocalFree(pszText2);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Handles the parent dialog for list view dialog.
|
||
|
static BOOL CALLBACK ListView_ParentDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static LVITEM lvi;
|
||
|
static POLDITEM poi;
|
||
|
static TCHAR szSectionName[32],
|
||
|
szNumber[4];
|
||
|
static BOOL bRes = FALSE;
|
||
|
static int i;
|
||
|
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
|
||
|
if (uMsg == WM_NOTIFY_OUTER_NEXT && wParam == 1)
|
||
|
{
|
||
|
pushstring(OUT_ENDSTACK);
|
||
|
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
||
|
lvi.iSubItem = 0;
|
||
|
lvi.pszText = pszValue;
|
||
|
lvi.cchTextMax = g_stringsize;
|
||
|
|
||
|
// No check boxes.
|
||
|
if (!g_iCheckBoxes)
|
||
|
{
|
||
|
for (i=0; i<g_iListItemCount; i++)
|
||
|
{
|
||
|
// Get item.
|
||
|
lvi.stateMask = LVIS_SELECTED;
|
||
|
lvi.iItem = i;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
// Get old item info.
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
|
||
|
// Get INI file section.
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, poi->iOldIndex);
|
||
|
|
||
|
// Is item selected?
|
||
|
if (lvi.state & LVIS_SELECTED)
|
||
|
{
|
||
|
// Add item text to stack.
|
||
|
if (g_bReturnItemText)
|
||
|
pushstring(lvi.pszText);
|
||
|
// Add item number to stack.
|
||
|
else
|
||
|
{
|
||
|
wsprintf(szNumber, TEXT("%i"), poi->iOldIndex);
|
||
|
pushstring(szNumber);
|
||
|
}
|
||
|
// Save selected state in INI file.
|
||
|
WriteINIStr(szSectionName, KEY_SELECTED, TEXT("1"));
|
||
|
}
|
||
|
else
|
||
|
// Save selected state in INI file.
|
||
|
WriteINIStr(szSectionName, KEY_SELECTED, TEXT("0"));
|
||
|
|
||
|
// Save list item text if it has been modified.
|
||
|
if (g_bLabelEdit)
|
||
|
if (!poi->bDisableEdit)
|
||
|
if (lstrcmp(poi->pszOldText, lvi.pszText) != 0)
|
||
|
WriteINIStr(szSectionName, KEY_TEXT, lvi.pszText);
|
||
|
}
|
||
|
}
|
||
|
// With check boxes.
|
||
|
else
|
||
|
{
|
||
|
for (i=0; i<g_iListItemCount; i++)
|
||
|
{
|
||
|
// Get item.
|
||
|
lvi.iItem = i;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
// Get old item info.
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
|
||
|
// Get INI file section.
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, poi->iOldIndex);
|
||
|
// Is item checked?
|
||
|
if (poi->iChecked)
|
||
|
{
|
||
|
// Add item text to stack.
|
||
|
if (g_bReturnItemText)
|
||
|
pushstring(lvi.pszText);
|
||
|
// Add item number to stack.
|
||
|
else
|
||
|
{
|
||
|
wsprintf(szNumber, TEXT("%i"), poi->iOldIndex);
|
||
|
pushstring(szNumber);
|
||
|
}
|
||
|
// Save checked state in INI file, unless its
|
||
|
// state cannot be changed.
|
||
|
if (!poi->iDisableCheck)
|
||
|
WriteINIStr(szSectionName, KEY_CHECKED, TEXT("1"));
|
||
|
}
|
||
|
else
|
||
|
// Save checked state in INI file, unless its
|
||
|
// state cannot be changed.
|
||
|
if (!poi->iDisableCheck)
|
||
|
WriteINIStr(szSectionName, KEY_CHECKED, TEXT("0"));
|
||
|
|
||
|
// Save list item text if it has been modified.
|
||
|
if (g_bLabelEdit)
|
||
|
if (!poi->bDisableEdit)
|
||
|
if (lstrcmp(poi->pszOldText, lvi.pszText) != 0)
|
||
|
WriteINIStr(szSectionName, KEY_TEXT, lvi.pszText);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
|
||
|
bRes = CallWindowProc(ParentDlgProcOld, hWnd, uMsg, wParam, lParam);
|
||
|
if (uMsg == WM_NOTIFY_OUTER_NEXT && !bRes)
|
||
|
{
|
||
|
if (wParam == -1)
|
||
|
g_is_back = TRUE;
|
||
|
else if (wParam == NOTIFY_BYE_BYE)
|
||
|
g_is_cancel = TRUE;
|
||
|
g_done = TRUE;
|
||
|
PostMessage(g_hDialog, WM_CLOSE, 0, 0);
|
||
|
}
|
||
|
return bRes;
|
||
|
}
|
||
|
|
||
|
// Handles ListView dialog.
|
||
|
static LRESULT CALLBACK ListView_DlgProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static HWND hNext = GetDlgItem(g_hWndParent, IDC_NEXT);
|
||
|
static BOOL bToggleNext = TRUE,
|
||
|
bItemSelected = FALSE,
|
||
|
bSingleSelect = FALSE,
|
||
|
bDialogShown = FALSE;
|
||
|
static TCHAR szSectionName[32],
|
||
|
szKeyName[32];
|
||
|
static int iValue,
|
||
|
iSectionCount,
|
||
|
iKeyCount;
|
||
|
static HIMAGELIST himlIcons,
|
||
|
himlState;
|
||
|
static LVITEM lvi;
|
||
|
static LVCOLUMN lvcNew;
|
||
|
static DWORD lStyle = 0;
|
||
|
static SORTBY sb;
|
||
|
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_SHOWWINDOW:
|
||
|
{
|
||
|
if (g_iCheckBoxes && !bDialogShown)
|
||
|
{
|
||
|
// Check all items to be checked (iChecked == TRUE).
|
||
|
for (int i=0; i<ListView_GetItemCount(g_hCtl); i++)
|
||
|
{
|
||
|
POLDITEM poi;
|
||
|
lvi.mask = LVIF_PARAM;
|
||
|
lvi.iItem = i;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
if (poi->iDisableCheck && (g_iCheckBoxes == 2))
|
||
|
{
|
||
|
if (poi->iDisableCheck == 2)
|
||
|
lvi.state = LVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = LVIS_IMAGE_DISCHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_IMAGE_DISUNCHECKED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = (g_iCheckBoxes == 2 ? LVIS_IMAGE_CHECKED : LVIS_CHECKED);
|
||
|
else
|
||
|
lvi.state = (g_iCheckBoxes == 2 ? LVIS_IMAGE_UNCHECKED : LVIS_UNCHECKED);
|
||
|
}
|
||
|
lvi.mask |= LVIF_STATE;
|
||
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Disable next button.
|
||
|
if (bToggleNext)
|
||
|
if (!ListView_IsItemChecked())
|
||
|
EnableWindow(hNext, FALSE);
|
||
|
|
||
|
bDialogShown = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case WM_INITDIALOG:
|
||
|
|
||
|
g_hCtl = GetDlgItem(hWndDlg, IDC_LIST);
|
||
|
lStyle = GetWindowLongPtr(g_hCtl, GWL_STYLE);
|
||
|
lvcNew.iSubItem = 0;
|
||
|
sb.iColumn = 1;
|
||
|
sb.iSort = -1;
|
||
|
{
|
||
|
// Full row select always.
|
||
|
ListView_SetExtendedListViewStyle(g_hCtl, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
|
||
|
|
||
|
// Disable the next button and re-enable when a item is selected or checked?
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_NEXTTOGGLE, 0) == 0)
|
||
|
bToggleNext = FALSE;
|
||
|
|
||
|
// Do not allow item selection.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_NOITEMSELECT, 0) == 1)
|
||
|
g_bNoItemSelect = TRUE;
|
||
|
|
||
|
// Return selected/checked items by item text rather than item number.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_RETURNITEMTEXT, 0) == 1)
|
||
|
g_bReturnItemText = TRUE;
|
||
|
|
||
|
// Allow column clicking. If sorting is enabled, will sort list by column.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_SORTBYCOLUMNCLICK, 0) == 0)
|
||
|
lStyle |= LVS_NOSORTHEADER;
|
||
|
|
||
|
// Add icon files to image list.
|
||
|
if (himlIcons = GetIcons())
|
||
|
ListView_SetImageList(g_hCtl, himlIcons, LVSIL_SMALL);
|
||
|
|
||
|
// Add check boxes to the list view.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_CHECKBOXES, 0))
|
||
|
{
|
||
|
g_iCheckBoxes = TRUE;
|
||
|
|
||
|
// Use NSIS check bitmap for state image list.
|
||
|
if (ReadINIStr(pszValue, SEC_SETTINGS, KEY_USECHECKBITMAP, TEXT("1")) && lstrcmp(pszValue, TEXT("0")) != 0)
|
||
|
{
|
||
|
if (himlState = GetStateImage(pszValue))
|
||
|
ListView_SetImageList(g_hCtl, himlState, LVSIL_STATE);
|
||
|
else
|
||
|
ListView_SetExtendedListViewStyle(g_hCtl, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_LABELTIP);
|
||
|
}
|
||
|
else
|
||
|
ListView_SetExtendedListViewStyle(g_hCtl, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_LABELTIP);
|
||
|
}
|
||
|
|
||
|
// Hide column headers.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_COLHEADER, 0) == 0)
|
||
|
{
|
||
|
RECT r;
|
||
|
GetClientRect(g_hCtl, &r);
|
||
|
lStyle |= LVS_NOCOLUMNHEADER;
|
||
|
lvcNew.mask = LVCF_TEXT | LVCF_WIDTH;
|
||
|
lvcNew.pszText = TEXT("");
|
||
|
lvcNew.cx = r.right-6;
|
||
|
ListView_InsertColumn(g_hCtl, lvcNew.iSubItem, &lvcNew);
|
||
|
}
|
||
|
|
||
|
// List view is single select.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_SINGLESELECT, 0))
|
||
|
{
|
||
|
bSingleSelect = TRUE;
|
||
|
lStyle |= LVS_SINGLESEL;
|
||
|
}
|
||
|
// Items are editable.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_LABELEDIT, 0))
|
||
|
{
|
||
|
g_bLabelEdit = TRUE;
|
||
|
lStyle |= LVS_EDITLABELS;
|
||
|
}
|
||
|
|
||
|
// Sort list view items alphabetically in ascending order.
|
||
|
if (ReadINIStr(pszValue, SEC_SETTINGS, KEY_SORT, TEXT("none")))
|
||
|
{
|
||
|
if (lstrcmpi(pszValue, TEXT("ascending")) == 0)
|
||
|
{
|
||
|
sb.iSort = 0;
|
||
|
ReadINIInt(sb.iColumn, SEC_SETTINGS, KEY_SORTBYCOLUMN, 1);
|
||
|
}
|
||
|
else if (lstrcmpi(pszValue, TEXT("descending")) == 0)
|
||
|
{
|
||
|
sb.iSort = 1;
|
||
|
ReadINIInt(sb.iColumn, SEC_SETTINGS, KEY_SORTBYCOLUMN, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add column headings to list view.
|
||
|
if ((lStyle & LVS_NOCOLUMNHEADER) != LVS_NOCOLUMNHEADER)
|
||
|
{
|
||
|
wsprintf(szKeyName, TEXT("%s%i"), KEY_COLUMN, iKeyCount = 1);
|
||
|
while (ReadINIStr(pszValue, SEC_COLUMNS, szKeyName, TEXT("")))
|
||
|
{
|
||
|
// Set column text.
|
||
|
lvcNew.mask = LVCF_TEXT | LVCF_WIDTH;
|
||
|
lvcNew.pszText = pszValue;
|
||
|
lvcNew.cchTextMax = g_stringsize;
|
||
|
|
||
|
// Set column width.
|
||
|
wsprintf(szKeyName, TEXT("%s%s"), szKeyName, KEY_WIDTH);
|
||
|
ReadINIInt(iValue, SEC_COLUMNS, szKeyName, 100);
|
||
|
lvcNew.cx = iValue;
|
||
|
|
||
|
// Add column.
|
||
|
ListView_InsertColumn(g_hCtl, ++lvcNew.iSubItem, &lvcNew);
|
||
|
|
||
|
// Next column.
|
||
|
wsprintf(szKeyName, TEXT("%s%i"), KEY_COLUMN, ++iKeyCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add list items.
|
||
|
g_iListItemCount = 0;
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, iSectionCount = 1);
|
||
|
while (ReadINIStr(pszValue, szSectionName, KEY_TEXT, TEXT("")))
|
||
|
{
|
||
|
// Set general item properties.
|
||
|
lvi.iSubItem = 0;
|
||
|
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
||
|
lvi.pszText = pszValue;
|
||
|
lvi.cchTextMax = g_stringsize;
|
||
|
lvi.iItem = g_iListItemCount;
|
||
|
|
||
|
// Store original item info in item tag.
|
||
|
lvi.lParam = (LPARAM)CreateOldItem(iSectionCount, szSectionName, pszValue);
|
||
|
|
||
|
// Increment item count.
|
||
|
g_iListItemCount++;
|
||
|
|
||
|
// Have an image list present?
|
||
|
if (himlIcons)
|
||
|
{
|
||
|
// Setting an icon on the item?
|
||
|
if (ReadINIInt(iValue, szSectionName, KEY_ICONINDEX, 0) != 0)
|
||
|
{
|
||
|
lvi.mask |= LVIF_IMAGE;
|
||
|
lvi.iImage = iValue-1; // Conversion to zero-based.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Select item if required.
|
||
|
if (ReadINIInt(iValue, szSectionName, KEY_SELECTED, 0))
|
||
|
{
|
||
|
if ((lStyle & LVS_SINGLESEL) == LVS_SINGLESEL)
|
||
|
{
|
||
|
// If we're using single selection, only
|
||
|
// select one item.
|
||
|
if (!bItemSelected)
|
||
|
{
|
||
|
lvi.mask |= LVIF_STATE;
|
||
|
lvi.stateMask |= LVIS_SELECTED;
|
||
|
lvi.state |= LVIS_SELECTED;
|
||
|
bItemSelected = TRUE;
|
||
|
}
|
||
|
}
|
||
|
// Using multiple selection.
|
||
|
else
|
||
|
{
|
||
|
lvi.mask |= LVIF_STATE;
|
||
|
lvi.stateMask |= LVIS_SELECTED;
|
||
|
lvi.state |= LVIS_SELECTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add list view item.
|
||
|
ListView_InsertItem(g_hCtl, &lvi);
|
||
|
|
||
|
// Set sub item texts.
|
||
|
wsprintf(szKeyName, TEXT("%s%i"), KEY_SUBITEM, iKeyCount = 1);
|
||
|
while (ReadINIStr(pszValue, szSectionName, szKeyName, TEXT("")))
|
||
|
{
|
||
|
// Set sub item text.
|
||
|
lvi.iSubItem++;
|
||
|
ListView_SetItemText(g_hCtl, lvi.iItem, lvi.iSubItem, pszValue);
|
||
|
// Next sub item.
|
||
|
wsprintf(szKeyName, TEXT("%s%i"), KEY_SUBITEM, ++iKeyCount);
|
||
|
}
|
||
|
|
||
|
// Next item.
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, ++iSectionCount);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
SetCommonTexts(hWndDlg);
|
||
|
SetWindowLongPtr(g_hCtl, GWL_STYLE, lStyle);
|
||
|
|
||
|
// Sort list view items.
|
||
|
if (sb.iSort != -1)
|
||
|
ListView_SortItemsEx(g_hCtl, ListView_CompareFunc, &sb);
|
||
|
|
||
|
// Set sub item to 1 now we're done using it.
|
||
|
lvi.iSubItem = 0;
|
||
|
|
||
|
// Focus list view control.
|
||
|
SetFocus(g_hCtl);
|
||
|
|
||
|
break;
|
||
|
case WM_CONTEXTMENU:
|
||
|
{
|
||
|
// Display a popup menu with check/uncheck all or select/unselect all options.
|
||
|
if ((wParam == (WPARAM)g_hCtl))
|
||
|
{
|
||
|
// Only display the menu if check boxes are enabled,
|
||
|
// multiple selection is supported,
|
||
|
// there is 1 or more items in the list.
|
||
|
if ((g_iCheckBoxes || !bSingleSelect) && (iValue = ListView_GetItemCount(g_hCtl)))
|
||
|
{
|
||
|
HMENU hMenu = CreatePopupMenu();
|
||
|
POINT pt;
|
||
|
int iSelection;
|
||
|
if (g_iCheckBoxes)
|
||
|
{
|
||
|
AppendMenu(hMenu, MF_STRING, 1, TEXT_CHECKALL);
|
||
|
AppendMenu(hMenu, MF_STRING, 2, TEXT_UNCHECKALL);
|
||
|
}
|
||
|
if (!bSingleSelect && !g_bNoItemSelect)
|
||
|
{
|
||
|
AppendMenu(hMenu, MF_STRING, 3, TEXT_SELECTALL);
|
||
|
AppendMenu(hMenu, MF_STRING, 4, TEXT_UNSELECTALL);
|
||
|
}
|
||
|
// Get the position to display the popup menu.
|
||
|
if (lParam == ((UINT)-1))
|
||
|
{
|
||
|
RECT r;
|
||
|
GetWindowRect(g_hCtl, &r);
|
||
|
pt.x = r.left;
|
||
|
pt.y = r.top;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pt.x = GET_X_LPARAM(lParam);
|
||
|
pt.y = GET_Y_LPARAM(lParam);
|
||
|
}
|
||
|
// Display the menu and detect which item was selected.
|
||
|
iSelection = TrackPopupMenu(hMenu, TPM_NONOTIFY|TPM_RETURNCMD, pt.x, pt.y, 0, g_hCtl, 0);
|
||
|
if (iSelection)
|
||
|
{
|
||
|
for (int i=0; i<iValue; i++)
|
||
|
{
|
||
|
lvi.iItem = i;
|
||
|
|
||
|
// Check or uncheck items.
|
||
|
if ((iSelection == 1) || (iSelection == 2))
|
||
|
{
|
||
|
POLDITEM poi;
|
||
|
lvi.mask = LVIF_PARAM;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
|
||
|
if (!poi->iDisableCheck)
|
||
|
{
|
||
|
if (iSelection == 1)
|
||
|
{
|
||
|
if (g_iCheckBoxes == 2)
|
||
|
lvi.state = LVIS_IMAGE_CHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_CHECKED;
|
||
|
poi->iChecked = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (g_iCheckBoxes == 2)
|
||
|
lvi.state = LVIS_IMAGE_UNCHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_UNCHECKED;
|
||
|
poi->iChecked = FALSE;
|
||
|
}
|
||
|
|
||
|
lvi.mask |= LVIF_STATE;
|
||
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lvi.mask = LVIF_STATE;
|
||
|
lvi.stateMask = LVIS_SELECTED;
|
||
|
if (iSelection == 3)
|
||
|
lvi.state = LVIS_SELECTED;
|
||
|
else
|
||
|
lvi.state = 0;
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WM_NOTIFY:
|
||
|
{
|
||
|
NMHDR* pnmh = (NMHDR*)lParam;
|
||
|
switch (pnmh->code)
|
||
|
{
|
||
|
case LVN_BEGINLABELEDIT:
|
||
|
{
|
||
|
NMLVDISPINFO* pdi = (NMLVDISPINFO*)lParam;
|
||
|
POLDITEM poi;
|
||
|
|
||
|
// Get OLDITEM info.
|
||
|
pdi->item.mask = LVIF_PARAM;
|
||
|
ListView_GetItem(g_hCtl, &pdi->item);
|
||
|
poi = (POLDITEM)pdi->item.lParam;
|
||
|
|
||
|
// Find out if the item label can be edited.
|
||
|
if (poi->bDisableEdit)
|
||
|
{
|
||
|
// No, so press enter to cancel edit.
|
||
|
keybd_event(VK_RETURN, 0, 0, 0);
|
||
|
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
|
||
|
}
|
||
|
bResult = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case LVN_ENDLABELEDIT:
|
||
|
{
|
||
|
NMLVDISPINFO* pdi = (NMLVDISPINFO*)lParam;
|
||
|
// Label is being edited.
|
||
|
if (pdi->item.pszText != NULL)
|
||
|
ListView_SetItemText(g_hCtl, pdi->item.iItem, 0, pdi->item.pszText);
|
||
|
bResult = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case LVN_COLUMNCLICK:
|
||
|
{
|
||
|
NMLISTVIEW* pnmv = (NMLISTVIEW*)lParam;
|
||
|
// Sort list view by selected column.
|
||
|
if (sb.iSort == 0)
|
||
|
{
|
||
|
// Clicking the same column twice?
|
||
|
// Will reverse sort order.
|
||
|
if (pnmv->iSubItem == sb.iColumn-1)
|
||
|
sb.iSort = 1;
|
||
|
else
|
||
|
sb.iColumn = pnmv->iSubItem+1;
|
||
|
// Sort them!
|
||
|
ListView_SortItemsEx(g_hCtl, ListView_CompareFunc, &sb);
|
||
|
}
|
||
|
else if (sb.iSort == 1)
|
||
|
{
|
||
|
// Clicking the same column twice?
|
||
|
// Will reverse sort order.
|
||
|
if (pnmv->iSubItem == sb.iColumn-1)
|
||
|
sb.iSort = 0;
|
||
|
else
|
||
|
sb.iColumn = pnmv->iSubItem+1;
|
||
|
// Sort them!
|
||
|
ListView_SortItemsEx(g_hCtl, ListView_CompareFunc, &sb);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case LVN_ITEMCHANGED:
|
||
|
{
|
||
|
NMLISTVIEW* pnmv = (NMLISTVIEW*)lParam;
|
||
|
// There is a bug where double clicking on the left or right margin of an item
|
||
|
// will change the state image incorrectly. This corrects the effects of the bug.
|
||
|
if (g_iCheckBoxes)
|
||
|
{
|
||
|
POLDITEM poi = (POLDITEM)pnmv->lParam;
|
||
|
if (g_iCheckBoxes == 2)
|
||
|
{
|
||
|
if (poi->iDisableCheck)
|
||
|
{
|
||
|
if (poi->iDisableCheck == 2)
|
||
|
lvi.state = LVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = LVIS_IMAGE_DISCHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_IMAGE_DISUNCHECKED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = LVIS_IMAGE_CHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_IMAGE_UNCHECKED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = LVIS_CHECKED;
|
||
|
else
|
||
|
lvi.state = LVIS_UNCHECKED;
|
||
|
}
|
||
|
lvi.mask = LVIF_STATE;
|
||
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
// Prevent selection of an item.
|
||
|
if (g_bNoItemSelect)
|
||
|
{
|
||
|
if (pnmv->iItem != -1)
|
||
|
if (pnmv->uNewState & LVIS_SELECTED)
|
||
|
{
|
||
|
lvi.mask = LVIF_STATE;
|
||
|
lvi.iItem = pnmv->iItem;
|
||
|
lvi.stateMask = LVIS_SELECTED;
|
||
|
lvi.state = 0;
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
}
|
||
|
else if (bToggleNext && !g_iCheckBoxes)
|
||
|
{
|
||
|
// Enable Next if there are one or more
|
||
|
// selected items.
|
||
|
if (ListView_GetSelectedCount(g_hCtl))
|
||
|
EnableWindow(hNext, TRUE);
|
||
|
// Otherwise, disable Next button.
|
||
|
else
|
||
|
EnableWindow(hNext, FALSE);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
// List view was clicked on.
|
||
|
case NM_DBLCLK:
|
||
|
case NM_CLICK:
|
||
|
{
|
||
|
// This contains the sub item index if it was clicked on.
|
||
|
// We can ignore those clicks on sub items because they have no
|
||
|
// effect on the check boxes.
|
||
|
NMITEMACTIVATE *nmlvi = (NMITEMACTIVATE*)lParam;
|
||
|
// The point at which the click took place
|
||
|
// so we can perform a 'hit test'.
|
||
|
POINT p;
|
||
|
LVHITTESTINFO lvhti;
|
||
|
|
||
|
// Do not continue if check boxes are not enabled.
|
||
|
if (!g_iCheckBoxes)
|
||
|
break;
|
||
|
|
||
|
// Get mouse cursor position in tree view.
|
||
|
GetCursorPos(&p);
|
||
|
ScreenToClient(g_hCtl, &p);
|
||
|
lvhti.pt.x = p.x;
|
||
|
lvhti.pt.y = p.y;
|
||
|
|
||
|
// Get check box user just clicked on.
|
||
|
if ((lvi.iItem = ListView_HitTest(g_hCtl, &lvhti)) != -1)
|
||
|
{
|
||
|
POLDITEM poi;
|
||
|
|
||
|
// Get item.
|
||
|
lvi.mask = LVIF_PARAM | LVIF_STATE;
|
||
|
ListView_GetItem(g_hCtl, &lvi);
|
||
|
|
||
|
// Get OLDITEM info.
|
||
|
poi = (POLDITEM)lvi.lParam;
|
||
|
|
||
|
lvi.mask = LVIF_STATE;
|
||
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
||
|
|
||
|
// Clicked on a check box?
|
||
|
if ((lvhti.flags & LVHT_ONITEMSTATEICON) && !nmlvi->iSubItem)
|
||
|
{
|
||
|
// Don't do anything if we are using the check bitmap
|
||
|
// and the this check box is disabled.
|
||
|
if (!poi->iDisableCheck && (g_iCheckBoxes == 2))
|
||
|
{
|
||
|
// Set check state.
|
||
|
if (poi->iChecked == TRUE)
|
||
|
{
|
||
|
lvi.state = LVIS_IMAGE_UNCHECKED;
|
||
|
poi->iChecked = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lvi.state = LVIS_IMAGE_CHECKED;
|
||
|
poi->iChecked = TRUE;
|
||
|
}
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
|
||
|
// Disable next button.
|
||
|
if (bToggleNext)
|
||
|
{
|
||
|
if (ListView_IsItemChecked())
|
||
|
EnableWindow(hNext, TRUE);
|
||
|
else
|
||
|
EnableWindow(hNext, FALSE);
|
||
|
}
|
||
|
}
|
||
|
// If we aren't using the check bitamp...
|
||
|
else if (g_iCheckBoxes == 1)
|
||
|
{
|
||
|
// The node check state cannot be changed...
|
||
|
if (poi->iDisableCheck)
|
||
|
{
|
||
|
// Check box must stay checked.
|
||
|
if (poi->iChecked)
|
||
|
lvi.state = LVIS_UNCHECKED;
|
||
|
// Check box must stay unchecked.
|
||
|
else
|
||
|
lvi.state = LVIS_CHECKED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Check box is to be unchecked.
|
||
|
if (poi->iChecked)
|
||
|
poi->iChecked = FALSE;
|
||
|
// Check box is to be checked.
|
||
|
else
|
||
|
poi->iChecked = TRUE;
|
||
|
|
||
|
lvi.mask = LVIF_PARAM;
|
||
|
}
|
||
|
ListView_SetItem(g_hCtl, &lvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WM_DESTROY:
|
||
|
{
|
||
|
ListView_FreeParams();
|
||
|
}
|
||
|
break;
|
||
|
case WM_CTLCOLORSTATIC:
|
||
|
case WM_CTLCOLOREDIT:
|
||
|
case WM_CTLCOLORDLG:
|
||
|
case WM_CTLCOLORBTN:
|
||
|
case WM_CTLCOLORLISTBOX:
|
||
|
// Let the NSIS window handle colours, it knows best.
|
||
|
bResult = SendMessage(g_hWndParent, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
// Search for all checked nodes and push them onto NSIS stack.
|
||
|
void TreeView_SaveState(HTREEITEM htvi)
|
||
|
{
|
||
|
static HTREEITEM htvic, htvicc;
|
||
|
static TVITEM tvi;
|
||
|
static POLDITEM poi;
|
||
|
static TCHAR szSectionName[32],
|
||
|
szNumber[4];
|
||
|
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Get node.
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM | TVIF_STATE;
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
tvi.hItem = htvi;
|
||
|
tvi.pszText = pszValue;
|
||
|
tvi.cchTextMax = g_stringsize;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
|
||
|
// Get old node info.
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
// Get INI file section.
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, poi->iOldIndex);
|
||
|
|
||
|
// Can check box state be changed?
|
||
|
// If not, then no state changes will have occured.
|
||
|
if (!poi->iDisableCheck)
|
||
|
{
|
||
|
// Is item checked?
|
||
|
if (poi->iChecked)
|
||
|
{
|
||
|
// Push checked item number or text onto stack.
|
||
|
if (!g_bNoItemSelect)
|
||
|
{
|
||
|
// Add item text to stack.
|
||
|
if (g_bReturnItemText)
|
||
|
pushstring(tvi.pszText);
|
||
|
// Add item number to stack.
|
||
|
else
|
||
|
{
|
||
|
wsprintf(szNumber, TEXT("%i"), poi->iOldIndex);
|
||
|
pushstring(szNumber);
|
||
|
}
|
||
|
}
|
||
|
// Save checked state in INI file.
|
||
|
WriteINIStr(szSectionName, KEY_CHECKED, TEXT("1"));
|
||
|
}
|
||
|
else
|
||
|
// Save checked state in INI file.
|
||
|
WriteINIStr(szSectionName, KEY_CHECKED, TEXT("0"));
|
||
|
}
|
||
|
|
||
|
// Save list item text if it has been modified.
|
||
|
if (g_bLabelEdit)
|
||
|
if (!poi->bDisableEdit)
|
||
|
if (lstrcmp(poi->pszOldText, tvi.pszText) != 0)
|
||
|
WriteINIStr(szSectionName, KEY_TEXT, tvi.pszText);
|
||
|
|
||
|
// Next child node.
|
||
|
if (htvic = TreeView_GetChild(g_hCtl, htvi))
|
||
|
{
|
||
|
// Check if this node is expanded.
|
||
|
if (tvi.state & TVIS_EXPANDED)
|
||
|
WriteINIStr(szSectionName, KEY_EXPANDED, TEXT("1"));
|
||
|
else
|
||
|
WriteINIStr(szSectionName, KEY_EXPANDED, TEXT("0"));
|
||
|
TreeView_SaveState(htvic);
|
||
|
}
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
}
|
||
|
|
||
|
// Recursively check all child nodes.
|
||
|
void TreeView_CheckChildNodes(HTREEITEM htvi, BOOL state)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
TVITEM tvi;
|
||
|
POLDITEM poi;
|
||
|
do
|
||
|
{
|
||
|
// Get node.
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
// Check this node state is allowed to be changed...
|
||
|
if (!poi->iDisableCheck)
|
||
|
{
|
||
|
poi->iChecked = state;
|
||
|
if (state)
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_CHECKED : TVIS_CHECKED);
|
||
|
else
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_UNCHECKED : TVIS_UNCHECKED);
|
||
|
tvi.mask |= TVIF_STATE;
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
|
||
|
// Next child node.
|
||
|
if (htvic = TreeView_GetChild(g_hCtl, htvi))
|
||
|
TreeView_CheckChildNodes(htvic, state);
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
}
|
||
|
|
||
|
// Counts the total number of siblings of a node (including the node itself).
|
||
|
// The first child node in a tree must be passed.
|
||
|
void TreeView_GetSiblingCount(HTREEITEM htvi, int &iCheckedCount, int &iDisabledCheckedCount, int &iCount)
|
||
|
{
|
||
|
TVITEM tvi;
|
||
|
do
|
||
|
{
|
||
|
(int*)iCount++;
|
||
|
|
||
|
// Get node.
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
|
||
|
// Is item checked...
|
||
|
if (((POLDITEM)tvi.lParam)->iChecked)
|
||
|
{
|
||
|
if (((POLDITEM)tvi.lParam)->iDisableCheck)
|
||
|
(int*)iDisabledCheckedCount++;
|
||
|
else
|
||
|
(int*)iCheckedCount++;
|
||
|
}
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
}
|
||
|
|
||
|
// Loops through parent nodes backwards to set their checked state.
|
||
|
void TreeView_SetParentNodeCheckState(HTREEITEM htvi)
|
||
|
{
|
||
|
TVITEM tvi;
|
||
|
POLDITEM poi;
|
||
|
while (htvi = TreeView_GetParent(g_hCtl, htvi))
|
||
|
{
|
||
|
// Get number of siblings.
|
||
|
int iCheckedCount = 0, iDisabledCheckedCount = 0, iCount = 0;
|
||
|
TreeView_GetSiblingCount(TreeView_GetChild(g_hCtl, htvi), iCheckedCount, iDisabledCheckedCount, iCount);
|
||
|
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
// Manage parent node states when using the check bitmap.
|
||
|
if (g_iCheckBoxes == 2)
|
||
|
{
|
||
|
// Uncheck parent node.
|
||
|
if ((iCheckedCount + iDisabledCheckedCount) == 0)
|
||
|
{
|
||
|
if (poi->iDisableCheck == 1)
|
||
|
tvi.state = TVIS_IMAGE_DISUNCHECKED;
|
||
|
else if (poi->iDisableCheck == 2)
|
||
|
tvi.state = TVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_UNCHECKED;
|
||
|
poi->iChecked = FALSE;
|
||
|
}
|
||
|
// Partially check parent node.
|
||
|
else if ((iCheckedCount + iDisabledCheckedCount) != iCount)
|
||
|
{
|
||
|
if (poi->iDisableCheck == 1)
|
||
|
tvi.state = TVIS_IMAGE_DISCHECKED;
|
||
|
else if (poi->iDisableCheck == 2)
|
||
|
tvi.state = TVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_PCHECKED;
|
||
|
|
||
|
if (iCheckedCount)
|
||
|
poi->iChecked = 3;
|
||
|
else
|
||
|
poi->iChecked = 2;
|
||
|
}
|
||
|
// Check parent node.
|
||
|
else
|
||
|
{
|
||
|
if (poi->iDisableCheck == 1)
|
||
|
tvi.state = TVIS_IMAGE_DISCHECKED;
|
||
|
else if (poi->iDisableCheck == 2)
|
||
|
tvi.state = TVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_CHECKED;
|
||
|
poi->iChecked = TRUE;
|
||
|
}
|
||
|
}
|
||
|
// Manage parent node states when not using the check bitmap.
|
||
|
else
|
||
|
{
|
||
|
// Uncheck parent node.
|
||
|
if (iCheckedCount != iCount)
|
||
|
{
|
||
|
tvi.state = TVIS_UNCHECKED;
|
||
|
poi->iChecked = FALSE;
|
||
|
}
|
||
|
// Check parent node.
|
||
|
else
|
||
|
{
|
||
|
tvi.state = TVIS_CHECKED;
|
||
|
poi->iChecked = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tvi.mask |= TVIF_STATE;
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Loops through all nodes to set the check state of all parent nodes.
|
||
|
void TreeView_SetAllParentNodeCheckState(HTREEITEM htvi)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
do
|
||
|
{
|
||
|
if (htvic = TreeView_GetChild(g_hCtl, htvi))
|
||
|
TreeView_SetAllParentNodeCheckState(htvic);
|
||
|
htvic = htvi;
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
TreeView_SetParentNodeCheckState(htvic);
|
||
|
}
|
||
|
|
||
|
// Check or uncheck all nodes in the tree view.
|
||
|
void TreeView_SetAllNodesCheckState(HTREEITEM htvi, BOOL state)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
TVITEM tvi;
|
||
|
POLDITEM poi;
|
||
|
do
|
||
|
{
|
||
|
htvic = TreeView_GetChild(g_hCtl, htvi);
|
||
|
if ((g_bParentCheck && !htvic) || !g_bParentCheck)
|
||
|
{
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
if (!poi->iDisableCheck)
|
||
|
{
|
||
|
tvi.mask |= TVIF_STATE;
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
|
||
|
poi->iChecked = state;
|
||
|
if (state)
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_CHECKED : TVIS_CHECKED);
|
||
|
else
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_UNCHECKED : TVIS_UNCHECKED);
|
||
|
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (htvic)
|
||
|
TreeView_SetAllNodesCheckState(htvic, state);
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
}
|
||
|
|
||
|
// Check all nodes that have iChecked = TRUE set.
|
||
|
void TreeView_CheckNodesToBeChecked(HTREEITEM htvi)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
TVITEM tvi;
|
||
|
POLDITEM poi;
|
||
|
do
|
||
|
{
|
||
|
htvic = TreeView_GetChild(g_hCtl, htvi);
|
||
|
if ((g_bParentCheck && !htvic) || !g_bParentCheck)
|
||
|
{
|
||
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
if (poi->iDisableCheck && (g_iCheckBoxes == 2))
|
||
|
{
|
||
|
if (poi->iDisableCheck == 2)
|
||
|
tvi.state = TVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked == TRUE)
|
||
|
tvi.state = TVIS_IMAGE_DISCHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_DISUNCHECKED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked == TRUE)
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_CHECKED : TVIS_CHECKED);
|
||
|
else
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_UNCHECKED : TVIS_UNCHECKED);
|
||
|
}
|
||
|
|
||
|
tvi.mask = TVIF_STATE | TVIF_HANDLE;
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
|
||
|
if (htvic)
|
||
|
TreeView_CheckNodesToBeChecked(htvic);
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
}
|
||
|
|
||
|
// Get number of checked nodes.
|
||
|
int TreeView_IsNodeChecked(HTREEITEM htvi)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
TVITEM tvi;
|
||
|
do
|
||
|
{
|
||
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
|
||
|
if (((POLDITEM)tvi.lParam)->iChecked == TRUE)
|
||
|
return TRUE;
|
||
|
|
||
|
if (htvic = TreeView_GetChild(g_hCtl, htvi))
|
||
|
if (TreeView_IsNodeChecked(htvic))
|
||
|
return TRUE;
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Frees memory allocated for each tree view node.
|
||
|
void TreeView_FreeParams(HTREEITEM htvi)
|
||
|
{
|
||
|
HTREEITEM htvic;
|
||
|
TVITEM tvi;
|
||
|
POLDITEM poi;
|
||
|
tvi.mask = TVIF_PARAM;
|
||
|
do
|
||
|
{
|
||
|
// Get lParam.
|
||
|
tvi.hItem = htvi;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
|
||
|
// Get OLDITEM data.
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
// Free memory allocated.
|
||
|
GlobalFree(poi->pszOldText);
|
||
|
GlobalFree(poi);
|
||
|
|
||
|
// Next child node.
|
||
|
if (htvic = TreeView_GetChild(g_hCtl, htvi))
|
||
|
TreeView_FreeParams(htvic);
|
||
|
}
|
||
|
while (htvi = TreeView_GetNextSibling(g_hCtl, htvi));
|
||
|
}
|
||
|
|
||
|
// Handles the parent dialog for list view dialog.
|
||
|
static BOOL CALLBACK TreeView_ParentDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static HTREEITEM htvi;
|
||
|
static TVITEM tvi;
|
||
|
static POLDITEM poi;
|
||
|
static BOOL bRes = FALSE;
|
||
|
static int i;
|
||
|
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
|
||
|
if (uMsg == WM_NOTIFY_OUTER_NEXT && wParam == 1)
|
||
|
{
|
||
|
pushstring(OUT_ENDSTACK);
|
||
|
|
||
|
// Save the tree view state.
|
||
|
if (htvi = TreeView_GetRoot(g_hCtl))
|
||
|
TreeView_SaveState(htvi);
|
||
|
|
||
|
// If items can be selected, return
|
||
|
// the selected item on the stack.
|
||
|
if (!g_bNoItemSelect && !g_iCheckBoxes)
|
||
|
{
|
||
|
if ((tvi.hItem = TreeView_GetSelection(g_hCtl)))
|
||
|
{
|
||
|
|
||
|
// Add item text to stack.
|
||
|
if (g_bReturnItemText)
|
||
|
{
|
||
|
tvi.mask = TVIF_TEXT | TVIF_HANDLE;
|
||
|
tvi.pszText = pszValue;
|
||
|
tvi.cchTextMax = g_stringsize;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
pushstring(tvi.pszText);
|
||
|
}
|
||
|
// Add item number to stack.
|
||
|
else
|
||
|
{
|
||
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
wsprintf(pszValue, TEXT("%i"), poi->iOldIndex);
|
||
|
pushstring(pszValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
|
||
|
bRes = CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))ParentDlgProcOld,hWnd,uMsg,wParam,lParam);
|
||
|
if (uMsg == WM_NOTIFY_OUTER_NEXT && !bRes)
|
||
|
{
|
||
|
if (wParam == -1)
|
||
|
g_is_back = TRUE;
|
||
|
else if (wParam == NOTIFY_BYE_BYE)
|
||
|
g_is_cancel = TRUE;
|
||
|
g_done = TRUE;
|
||
|
PostMessage(g_hDialog, WM_CLOSE, 0, 0);
|
||
|
}
|
||
|
return bRes;
|
||
|
}
|
||
|
|
||
|
// Handles TreeView dialog.
|
||
|
static LRESULT CALLBACK TreeView_DlgProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static HWND hNext = GetDlgItem(g_hWndParent, IDC_NEXT);
|
||
|
static BOOL bToggleNext = TRUE,
|
||
|
bDialogShown = FALSE;
|
||
|
static TCHAR szSectionName[32],
|
||
|
szKeyName[32];
|
||
|
static int iValue,
|
||
|
iSectionCount,
|
||
|
iKeyCount,
|
||
|
ihtviListCount,
|
||
|
ihtviListIndex;
|
||
|
static HIMAGELIST himlIcons,
|
||
|
himlState;
|
||
|
static TVITEM tvi;
|
||
|
static TVITEM tvip;
|
||
|
static HTREEITEM htvi;
|
||
|
static HTREEITEM htviList[8];
|
||
|
static TVINSERTSTRUCT tviins;
|
||
|
static DWORD lStyle = 0;
|
||
|
static HICON hIcon;
|
||
|
|
||
|
PTCHAR pszValue = (PTCHAR)LocalAlloc(LPTR, sizeof(TCHAR)*g_stringsize);
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_SHOWWINDOW:
|
||
|
{
|
||
|
if (g_iCheckBoxes && !bDialogShown)
|
||
|
{
|
||
|
htvi = TreeView_GetRoot(g_hCtl);
|
||
|
|
||
|
// Check all nodes to be checked (iChecked == TRUE).
|
||
|
TreeView_CheckNodesToBeChecked(htvi);
|
||
|
|
||
|
// Set the state of all parent nodes.
|
||
|
if (g_bParentCheck)
|
||
|
TreeView_SetAllParentNodeCheckState(htvi);
|
||
|
}
|
||
|
|
||
|
// Disable next button.
|
||
|
if (bToggleNext)
|
||
|
if (!TreeView_IsNodeChecked(TreeView_GetRoot(g_hCtl)))
|
||
|
EnableWindow(hNext, FALSE);
|
||
|
|
||
|
bDialogShown = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case WM_INITDIALOG:
|
||
|
|
||
|
g_hCtl = GetDlgItem(hWndDlg, IDC_LIST);
|
||
|
lStyle = GetWindowLongPtr(g_hCtl, GWL_STYLE);
|
||
|
{
|
||
|
// Disable the next button and re-enable when a item is selected or checked?
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_NEXTTOGGLE, 0) == 0)
|
||
|
bToggleNext = FALSE;
|
||
|
|
||
|
// Do not allow item selection.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_NOITEMSELECT, 0) == 1)
|
||
|
g_bNoItemSelect = TRUE;
|
||
|
|
||
|
// Return selected/checked items by item text rather than item number.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_RETURNITEMTEXT, 0) == 1)
|
||
|
g_bReturnItemText = TRUE;
|
||
|
|
||
|
// Parent nodes uncheck child nodes when checked.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_PARENTCHECK, 0))
|
||
|
g_bParentCheck = TRUE;
|
||
|
|
||
|
// Add icon files to image list.
|
||
|
if (himlIcons = GetIcons())
|
||
|
TreeView_SetImageList(g_hCtl, himlIcons, TVSIL_NORMAL);
|
||
|
|
||
|
// Add check boxes to the list view.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_CHECKBOXES, 0))
|
||
|
{
|
||
|
g_iCheckBoxes = TRUE;
|
||
|
|
||
|
// Use NSIS check bitmap for state image list.
|
||
|
if (ReadINIStr(pszValue, SEC_SETTINGS, KEY_USECHECKBITMAP, TEXT("1")) && lstrcmp(pszValue, TEXT("0")) != 0)
|
||
|
{
|
||
|
if (himlState = GetStateImage(pszValue))
|
||
|
{
|
||
|
TreeView_SetImageList(g_hCtl, himlState, TVSIL_STATE);
|
||
|
TreeView_SetItemHeight(g_hCtl, 16);
|
||
|
}
|
||
|
else
|
||
|
lStyle |= TVS_CHECKBOXES;
|
||
|
}
|
||
|
else
|
||
|
lStyle |= TVS_CHECKBOXES;
|
||
|
}
|
||
|
|
||
|
// All tree nodes have editable labels.
|
||
|
if (ReadINIInt(iValue, SEC_SETTINGS, KEY_LABELEDIT, 0))
|
||
|
{
|
||
|
g_bLabelEdit = TRUE;
|
||
|
lStyle |= TVS_EDITLABELS;
|
||
|
}
|
||
|
|
||
|
// Add tree nodes.
|
||
|
ihtviListCount = 1;
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, iSectionCount = 1);
|
||
|
while (ReadINIStr(pszValue, szSectionName, KEY_TEXT, TEXT("")))
|
||
|
{
|
||
|
// Set general item properties.
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM | TVIF_STATE;
|
||
|
tvi.pszText = pszValue;
|
||
|
tvi.cchTextMax = g_stringsize;
|
||
|
tvi.state = 0;
|
||
|
tvi.stateMask = 0;
|
||
|
|
||
|
// Store original item info in item tag.
|
||
|
tvi.lParam = (LPARAM)CreateOldItem(iSectionCount, szSectionName, pszValue);
|
||
|
|
||
|
// Have an image list present?
|
||
|
if (himlIcons)
|
||
|
{
|
||
|
// Setting an icon on the node?
|
||
|
if (ReadINIInt(iValue, szSectionName, KEY_ICONINDEX, 0) != 0)
|
||
|
{
|
||
|
tvi.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
||
|
tvi.iImage = iValue-1; // Conversion to zero-based.
|
||
|
tvi.iSelectedImage = iValue-1; // Conversion to zero-based.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// No position set, just insert under last inserted node!
|
||
|
if (ReadINIInt(ihtviListIndex, szSectionName, KEY_POSITION, 0) != 0)
|
||
|
{
|
||
|
ihtviListCount++;
|
||
|
if (ihtviListIndex > ihtviListCount)
|
||
|
ihtviListIndex = ihtviListCount;
|
||
|
if (ihtviListIndex-2 < 0)
|
||
|
tviins.hParent = TVI_ROOT;
|
||
|
else
|
||
|
tviins.hParent = htviList[ihtviListIndex-2];
|
||
|
}
|
||
|
else ihtviListIndex = ihtviListCount;
|
||
|
|
||
|
// Bold tree node?
|
||
|
if (ReadINIInt(iValue, szSectionName, KEY_BOLDTEXT, 0) == 1)
|
||
|
{
|
||
|
tvi.state |= TVIS_BOLD;
|
||
|
tvi.stateMask |= TVIS_BOLD;
|
||
|
}
|
||
|
|
||
|
// Expand tree node?
|
||
|
if (ReadINIInt(iValue, szSectionName, KEY_EXPANDED, 0) == 1)
|
||
|
{
|
||
|
tvi.state |= TVIS_EXPANDED;
|
||
|
tvi.stateMask |= TVIS_EXPANDED;
|
||
|
}
|
||
|
|
||
|
// Insert the new node.
|
||
|
tviins.item = tvi;
|
||
|
htvi = TreeView_InsertItem(g_hCtl, &tviins);
|
||
|
htviList[ihtviListIndex-1] = htvi;
|
||
|
|
||
|
// Next item.
|
||
|
wsprintf(szSectionName, TEXT("%s %i"), SEC_ITEM, ++iSectionCount);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
SetCommonTexts(hWndDlg);
|
||
|
SetWindowLongPtr(g_hCtl, GWL_STYLE, lStyle);
|
||
|
|
||
|
break;
|
||
|
case WM_CONTEXTMENU:
|
||
|
{
|
||
|
// Display a popup menu with check/uncheck all options.
|
||
|
if ((wParam == (WPARAM)g_hCtl))
|
||
|
{
|
||
|
// Only display the menu if there is at least 1 node
|
||
|
// and check boxes are enabled.
|
||
|
if (g_iCheckBoxes && TreeView_GetCount(g_hCtl))
|
||
|
{
|
||
|
HMENU hMenu = CreatePopupMenu();
|
||
|
POINT pt;
|
||
|
// Add the two options.
|
||
|
AppendMenu(hMenu, MF_STRING, 1, TEXT_CHECKALL);
|
||
|
AppendMenu(hMenu, MF_STRING, 2, TEXT_UNCHECKALL);
|
||
|
// Get the position to display the popup menu.
|
||
|
if (lParam == ((UINT)-1))
|
||
|
{
|
||
|
RECT r;
|
||
|
GetWindowRect(g_hCtl, &r);
|
||
|
pt.x = r.left;
|
||
|
pt.y = r.top;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pt.x = GET_X_LPARAM(lParam);
|
||
|
pt.y = GET_Y_LPARAM(lParam);
|
||
|
}
|
||
|
// Display the menu and detect which item was selected.
|
||
|
switch (TrackPopupMenu(hMenu, TPM_NONOTIFY|TPM_RETURNCMD, pt.x, pt.y, 0, g_hCtl, 0))
|
||
|
{
|
||
|
case 1:
|
||
|
TreeView_SetAllNodesCheckState(TreeView_GetRoot(g_hCtl), TRUE);
|
||
|
break;
|
||
|
case 2:
|
||
|
TreeView_SetAllNodesCheckState(TreeView_GetRoot(g_hCtl), FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Set the state of all parent nodes.
|
||
|
if (g_bParentCheck)
|
||
|
TreeView_SetAllParentNodeCheckState(htvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WM_NOTIFY:
|
||
|
{
|
||
|
NMHDR* pnmh = (NMHDR*)lParam;
|
||
|
switch (pnmh->code)
|
||
|
{
|
||
|
case TVN_SELCHANGED:
|
||
|
{
|
||
|
// Unselect any selected items.
|
||
|
if (!g_bLabelEdit && g_bNoItemSelect)
|
||
|
TreeView_SelectItem(g_hCtl, NULL);
|
||
|
}
|
||
|
break;
|
||
|
case TVN_BEGINLABELEDIT:
|
||
|
{
|
||
|
NMTVDISPINFO* ptvdi = (NMTVDISPINFO*)lParam;
|
||
|
POLDITEM poi;
|
||
|
// Get OLDITEM info.
|
||
|
ptvdi->item.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
TreeView_GetItem(g_hCtl, &ptvdi->item);
|
||
|
poi = (POLDITEM)ptvdi->item.lParam;
|
||
|
// Find out if the item label can be edited.
|
||
|
if (poi->bDisableEdit)
|
||
|
{
|
||
|
int i;
|
||
|
// No, so press tab to cancel edit.
|
||
|
for (i=0; i<4; i++)
|
||
|
{
|
||
|
// Press it 4 times to tab back to TV control.
|
||
|
keybd_event(VK_TAB, 0, 0, 0);
|
||
|
keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0);
|
||
|
}
|
||
|
}
|
||
|
bResult = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case TVN_ENDLABELEDIT:
|
||
|
{
|
||
|
NMTVDISPINFO* ptvdi = (NMTVDISPINFO*)lParam;
|
||
|
// Label is being edited.
|
||
|
if (ptvdi->item.pszText != NULL)
|
||
|
{
|
||
|
ptvdi->item.mask = TVIF_TEXT;
|
||
|
TreeView_SetItem(g_hCtl, &ptvdi->item);
|
||
|
}
|
||
|
bResult = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
// Tree view was clicked on.
|
||
|
case NM_DBLCLK:
|
||
|
case NM_CLICK:
|
||
|
{
|
||
|
// The point at which the click took place
|
||
|
// so we can perform a 'hit test'.
|
||
|
POINT p;
|
||
|
TVHITTESTINFO tvhti;
|
||
|
|
||
|
// Do not continue if check boxes are not enabled.
|
||
|
if (!g_iCheckBoxes)
|
||
|
break;
|
||
|
|
||
|
// Get mouse cursor position in tree view.
|
||
|
GetCursorPos(&p);
|
||
|
ScreenToClient(g_hCtl, &p);
|
||
|
tvhti.pt.x = p.x;
|
||
|
tvhti.pt.y = p.y;
|
||
|
|
||
|
// Get item user just clicked on.
|
||
|
if ((tvi.hItem = TreeView_HitTest(g_hCtl, &tvhti)) != NULL)
|
||
|
{
|
||
|
POLDITEM poi;
|
||
|
// Get item.
|
||
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
TreeView_GetItem(g_hCtl, &tvi);
|
||
|
// Get OLDITEM info.
|
||
|
poi = (POLDITEM)tvi.lParam;
|
||
|
|
||
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||
|
|
||
|
// Clicked on a check box?
|
||
|
if (tvhti.flags & TVHT_ONITEMSTATEICON)
|
||
|
{
|
||
|
// Don't do anything if we are using the check bitmap
|
||
|
// and the this check box is disabled.
|
||
|
if (!poi->iDisableCheck && (g_iCheckBoxes == 2))
|
||
|
{
|
||
|
|
||
|
// Manage the parent node.
|
||
|
if (g_bParentCheck && (htvi = TreeView_GetChild(g_hCtl, tvi.hItem)))
|
||
|
{
|
||
|
TreeView_CheckChildNodes(htvi, (poi->iChecked == 3 || poi->iChecked == 1 ? FALSE : TRUE));
|
||
|
TreeView_SetParentNodeCheckState(htvi);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Check box will be unchecked.
|
||
|
if (poi->iChecked == TRUE)
|
||
|
{
|
||
|
tvi.state = TVIS_IMAGE_UNCHECKED;
|
||
|
poi->iChecked = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tvi.state = TVIS_IMAGE_CHECKED;
|
||
|
poi->iChecked = TRUE;
|
||
|
}
|
||
|
tvi.mask |= TVIF_STATE;
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
|
||
|
TreeView_SetParentNodeCheckState(tvi.hItem);
|
||
|
}
|
||
|
|
||
|
// Disable next button.
|
||
|
if (bToggleNext)
|
||
|
{
|
||
|
if (TreeView_IsNodeChecked(TreeView_GetRoot(g_hCtl)))
|
||
|
EnableWindow(hNext, TRUE);
|
||
|
else
|
||
|
EnableWindow(hNext, FALSE);
|
||
|
}
|
||
|
}
|
||
|
// If we aren't using the check bitamp...
|
||
|
else if (g_iCheckBoxes == 1)
|
||
|
{
|
||
|
// The node check state cannot be changed...
|
||
|
if (poi->iDisableCheck)
|
||
|
{
|
||
|
// Check box must stay checked.
|
||
|
if (poi->iChecked)
|
||
|
{
|
||
|
if (pnmh->code == NM_DBLCLK)
|
||
|
tvi.state = TVIS_CHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_UNCHECKED;
|
||
|
}
|
||
|
// Check box must stay unchecked.
|
||
|
else
|
||
|
{
|
||
|
if (pnmh->code == NM_DBLCLK)
|
||
|
tvi.state = TVIS_UNCHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_CHECKED;
|
||
|
}
|
||
|
|
||
|
tvi.mask = TVIF_STATE | TVIF_HANDLE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tvi.mask = TVIF_PARAM | TVIF_HANDLE;
|
||
|
|
||
|
// Check box is to be unchecked.
|
||
|
if (poi->iChecked)
|
||
|
poi->iChecked = FALSE;
|
||
|
// Check box is to be checked.
|
||
|
else
|
||
|
poi->iChecked = TRUE;
|
||
|
|
||
|
// Manage the parent node.
|
||
|
if (g_bParentCheck)
|
||
|
{
|
||
|
if (htvi = TreeView_GetChild(g_hCtl, tvi.hItem))
|
||
|
{
|
||
|
TreeView_CheckChildNodes(htvi, poi->iChecked);
|
||
|
TreeView_SetParentNodeCheckState(htvi);
|
||
|
}
|
||
|
else
|
||
|
TreeView_SetParentNodeCheckState(tvi.hItem);
|
||
|
|
||
|
// Correct the parent node state as it is about to be toggled.
|
||
|
if (poi->iChecked)
|
||
|
{
|
||
|
if (pnmh->code == NM_DBLCLK)
|
||
|
tvi.state = TVIS_CHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_UNCHECKED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pnmh->code == NM_DBLCLK)
|
||
|
tvi.state = TVIS_UNCHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_CHECKED;
|
||
|
}
|
||
|
|
||
|
tvi.mask |= TVIF_STATE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
}
|
||
|
// There is a bug where double clicking on the left margin of the state image
|
||
|
// will change the state icon incorrectly. This corrects the effects of the bug.
|
||
|
else
|
||
|
{
|
||
|
if (poi->iDisableCheck && (g_iCheckBoxes == 2))
|
||
|
{
|
||
|
if (poi->iDisableCheck == 2)
|
||
|
tvi.state = TVIS_IMAGE_BLANK;
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked)
|
||
|
tvi.state = TVIS_IMAGE_DISCHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_DISUNCHECKED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (poi->iChecked == TRUE)
|
||
|
tvi.state = (g_iCheckBoxes == 2 ? TVIS_IMAGE_CHECKED : TVIS_CHECKED);
|
||
|
else if ((poi->iChecked >= 2) && (g_iCheckBoxes == 2))
|
||
|
tvi.state = TVIS_IMAGE_PCHECKED;
|
||
|
else
|
||
|
tvi.state = TVIS_IMAGE_UNCHECKED;
|
||
|
}
|
||
|
tvi.mask = TVIF_HANDLE | TVIF_STATE;
|
||
|
TreeView_SetItem(g_hCtl, &tvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WM_DESTROY:
|
||
|
{
|
||
|
TreeView_FreeParams(TreeView_GetRoot(g_hCtl));
|
||
|
}
|
||
|
break;
|
||
|
case WM_CTLCOLORSTATIC:
|
||
|
case WM_CTLCOLOREDIT:
|
||
|
case WM_CTLCOLORDLG:
|
||
|
case WM_CTLCOLORBTN:
|
||
|
case WM_CTLCOLORLISTBOX:
|
||
|
// Let the NSIS window handle colours, it knows best.
|
||
|
bResult = SendMessage(g_hWndParent, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
LocalFree(pszValue);
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
void CreateDialogs()
|
||
|
{
|
||
|
TCHAR szDialog[16];
|
||
|
popstring(g_szINIFilePath);
|
||
|
g_done = TRUE;
|
||
|
|
||
|
// Find out which page to use.
|
||
|
ReadINIStr(szDialog, SEC_SETTINGS, KEY_TYPE, TEXT("ListView"));
|
||
|
|
||
|
// Which page to use?
|
||
|
if (lstrcmpi(szDialog, DLG_LISTVIEW) == 0)
|
||
|
{
|
||
|
g_iDialog = 0;
|
||
|
g_hDialog = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_LISTVIEW), g_hWndParent, (DLGPROC)ListView_DlgProc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_iDialog = 1;
|
||
|
g_hDialog = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_TREEVIEW), g_hWndParent, (DLGPROC)TreeView_DlgProc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Plugin callback for new plugin API.
|
||
|
static UINT_PTR PluginCallback(enum NSPIM msg)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
NSISFUNC(InitDialog)
|
||
|
{
|
||
|
DLL_INIT();
|
||
|
|
||
|
if (!g_bInitDialog)
|
||
|
{
|
||
|
TCHAR szHWND[32];
|
||
|
CreateDialogs();
|
||
|
|
||
|
// Return page HWND.
|
||
|
wsprintf(szHWND, TEXT("%d"), g_hDialog);
|
||
|
pushstring(szHWND);
|
||
|
|
||
|
g_bInitDialog = TRUE;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
pushstring(OUT_ERROR);
|
||
|
}
|
||
|
|
||
|
NSISFUNC(Show)
|
||
|
{
|
||
|
DLL_INIT();
|
||
|
|
||
|
if (g_bInitDialog)
|
||
|
{
|
||
|
g_bInitDialog = FALSE;
|
||
|
ShowDialog();
|
||
|
}
|
||
|
else
|
||
|
pushstring(OUT_ERROR);
|
||
|
}
|
||
|
|
||
|
NSISFUNC(Dialog)
|
||
|
{
|
||
|
DLL_INIT();
|
||
|
|
||
|
if (!g_bInitDialog)
|
||
|
{
|
||
|
CreateDialogs();
|
||
|
ShowDialog();
|
||
|
}
|
||
|
else
|
||
|
pushstring(OUT_ERROR);
|
||
|
}
|
||
|
|
||
|
// Entry point for DLL.
|
||
|
BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||
|
{
|
||
|
g_hInstance=hInst;
|
||
|
return TRUE;
|
||
|
}
|