Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2088 lines
52 KiB

//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1993-1994
//
// File: recact.c
//
// This file contains the reconciliation-action control class code
//
//
// History:
// 08-12-93 ScottH Created.
//
//---------------------------------------------------------------------------
///////////////////////////////////////////////////// INCLUDES
#include "pch.h"
#include "reintinc.h"
#include "extra.h"
#include "resource.h"
#include "recact.h"
#include "dobj.h"
///////////////////////////////////////////////////// Globals
int g_cxIconSpacing = 0;
int g_cyIconSpacing = 0;
int g_cxBorder = 0;
int g_cyBorder = 0;
int g_cxMargin = 0;
int g_cxIcon = 0;
int g_cyIcon = 0;
int g_cxIconMargin = 0;
int g_cyIconMargin = 0;
int g_cxLabelMargin = 0;
int g_cyLabelSpace = 0;
//char const FAR c_szWinHelpFile[] = "windows.hlp";
///////////////////////////////////////////////////// CONTROLLING DEFINES
///////////////////////////////////////////////////// DEFINES
// Manifest constants
#define SIDE_INSIDE 0
#define SIDE_OUTSIDE 1
// These should be changed if the bitmap sizes change!!
#define CX_ACTIONBMP 26
#define CY_ACTIONBMP 26
#define RECOMPUTE (-1)
#define X_INCOLUMN (g_cxIcon*2)
// Image indexes
#define II_RIGHT 0
#define II_LEFT 1
#define II_CONFLICT 2
#define II_SKIP 3
#define II_MERGE 4
#define II_SOMETHING 5
#define II_UPTODATE 6
// Menu items
//
#define IDM_ACTIONFIRST 100
#define IDM_TOOUT 100
#define IDM_TOIN 101
#define IDM_SKIP 102
#define IDM_MERGE 103
#define IDM_ACTIONLAST 103
#define IDM_WHATSTHIS 104
///////////////////////////////////////////////////// TYPEDEFS
typedef struct tagRECACT
{
HWND hwnd;
HWND hwndLB;
HDC hdcOwn; // Own DC
HMENU hmenu; // Action and help context menu
HFONT hfont;
WNDPROC lpfnLBProc; // Default LB proc
HIMAGELIST himlAction; // imagelist for actions
HIMAGELIST himlCache; // control imagelist cache
HBITMAP hbmpBullet;
HBRUSH hbrBkgnd;
COLORREF clrBkgnd;
LONG lStyle; // Window style flags
// Metrics
int xAction;
int cxAction;
int cxItem; // Generic width of an item
int cxMenuCheck;
int cyMenuCheck;
int cyText;
int cxSideItem;
int cxEllipses;
} RECACT, FAR * LPRECACT;
#define RecAct_IsNoIcon(this) IsFlagSet((this)->lStyle, RAS_SINGLEITEM)
// Internal item data struct
//
typedef struct tagRA_PRIV
{
UINT uStyle; // One of RAIS_
UINT uAction; // One of RAIA_
FileInfo * pfi;
SIDEITEM siInside;
SIDEITEM siOutside;
LPARAM lParam;
DOBJ rgdobj[4]; // Array of Draw object info
int cx; // Bounding width and height
int cy;
} RA_PRIV, FAR * LPRA_PRIV;
#define IDOBJ_ACTION 3
// RecAction menu item definition structure. Used to define the
// context menu brought up in this control.
//
typedef struct tagRAMID
{
UINT idm; // Menu ID (for MENUITEMINFO struct)
UINT uAction; // One of RAIA_* flags
UINT ids; // Resource string ID
int iImage; // Index into himlAction
RECT rcExtent; // Extent rect of string
} RAMID, FAR * LPRAMID; // RecAction Menu Item Definition
// Help menu item definition structure. Used to define the help
// items in the context menu.
//
typedef struct tagHMID
{
UINT idm;
UINT ids;
} HMID;
///////////////////////////////////////////////////// MACROS
#define RecAct_DefProc DefWindowProc
#define RecActLB_DefProc CallWindowProc
// Instance data pointer macros
//
#define RecAct_GetPtr(hwnd) (LPRECACT)GetWindowLong(hwnd, 0)
#define RecAct_SetPtr(hwnd, lp) (LPRECACT)SetWindowLong(hwnd, 0, (LONG)(lp))
#define RecAct_GetCount(this) ListBox_GetCount((this)->hwndLB)
///////////////////////////////////////////////////// MODULE DATA
static char const c_szEllipses[] = "...";
static char const c_szDateDummy[] = "99/99/99 99:99PM";
// Map RAIA_* values to image indexes
//
static UINT const c_mpraiaiImage[] =
{ II_RIGHT, II_LEFT, II_SKIP, II_CONFLICT, II_MERGE, II_SOMETHING, II_UPTODATE };
// Map RAIA_* values to menu command positions
//
static UINT const c_mpraiaidmMenu[] =
{IDM_TOOUT, IDM_TOIN, IDM_SKIP, IDM_SKIP, IDM_MERGE, 0, 0 };
// Define the context menu layout
//
static RAMID const c_rgramid[] = {
{ IDM_TOOUT, RAIA_TOOUT, IDS_MENU_REPLACE, II_RIGHT, 0 },
{ IDM_TOIN, RAIA_TOIN, IDS_MENU_REPLACE, II_LEFT, 0 },
{ IDM_SKIP, RAIA_SKIP, IDS_MENU_SKIP, II_SKIP, 0 },
// Merge must be the last item!
{ IDM_MERGE, RAIA_MERGE, IDS_MENU_MERGE, II_MERGE, 0 },
};
static RAMID const c_rgramidCreates[] = {
{ IDM_TOOUT, RAIA_TOOUT, IDS_MENU_CREATE, II_RIGHT, 0 },
{ IDM_TOIN, RAIA_TOIN, IDS_MENU_CREATE, II_LEFT, 0 },
};
// Indexes into c_rgramidCreates
//
#define IRAMID_CREATEOUT 0
#define IRAMID_CREATEIN 1
static HMID const c_rghmid[] = {
{ IDM_WHATSTHIS, IDS_MENU_WHATSTHIS },
};
///////////////////////////////////////////////////// LOCAL PROCEDURES
LRESULT _export CALLBACK RecActLB_LBProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
///////////////////////////////////////////////////// PRIVATE FUNCTIONS
#ifdef DEBUG
LPCSTR PRIVATE DumpRecAction(
UINT uAction) // RAIA_
{
switch (uAction)
{
DEBUG_CASE_STRING( RAIA_TOOUT );
DEBUG_CASE_STRING( RAIA_TOIN );
DEBUG_CASE_STRING( RAIA_SKIP );
DEBUG_CASE_STRING( RAIA_CONFLICT );
DEBUG_CASE_STRING( RAIA_MERGE );
DEBUG_CASE_STRING( RAIA_SOMETHING );
DEBUG_CASE_STRING( RAIA_NOTHING );
DEBUG_CASE_STRING( RAIA_ORPHAN );
default: return "Unknown";
}
}
LPCSTR PRIVATE DumpSideItemState(
UINT uState) // SI_
{
switch (uState)
{
DEBUG_CASE_STRING( SI_UNCHANGED );
DEBUG_CASE_STRING( SI_CHANGED );
DEBUG_CASE_STRING( SI_NEW );
DEBUG_CASE_STRING( SI_NOEXIST );
DEBUG_CASE_STRING( SI_UNAVAILABLE );
DEBUG_CASE_STRING( SI_DELETED );
default: return "Unknown";
}
}
/*----------------------------------------------------------
Purpose:
Returns:
Cond: --
*/
void PUBLIC DumpTwinPair(
LPRA_ITEM pitem)
{
if (pitem)
{
char szBuf[MAXMSGLEN];
#define szDump "Dump TWINPAIR: "
#define szBlank " "
if (IsFlagClear(g_uDumpFlags, DF_TWINPAIR))
{
return;
}
wsprintf(szBuf, "%s.pszName = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->pszName));
OutputDebugString(szBuf);
wsprintf(szBuf, "%s.uStyle = %lx\r\n", (LPSTR)szBlank, pitem->uStyle);
OutputDebugString(szBuf);
wsprintf(szBuf, "%s.uAction = %s\r\n", (LPSTR)szBlank, DumpRecAction(pitem->uAction));
OutputDebugString(szBuf);
#undef szDump
#define szDump " Inside: "
wsprintf(szBuf, "%s.pszDir = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->siInside.pszDir));
OutputDebugString(szBuf);
wsprintf(szBuf, "%s.uState = %s\r\n", (LPSTR)szBlank, DumpSideItemState(pitem->siInside.uState));
OutputDebugString(szBuf);
#undef szDump
#define szDump " Outside: "
wsprintf(szBuf, "%s.pszDir = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->siOutside.pszDir));
OutputDebugString(szBuf);
wsprintf(szBuf, "%s.uState = %s\r\n", (LPSTR)szBlank, DumpSideItemState(pitem->siOutside.uState));
OutputDebugString(szBuf);
#undef szDump
#undef szBlank
}
}
#endif
/*----------------------------------------------------------
Purpose: Create a monochrome bitmap of the bullet, so we can
play with the colors later.
Returns: handle to bitmap
Cond: Caller must delete bitmap
*/
HBITMAP PRIVATE CreateBulletBitmap(
LPSIZE psize)
{
HDC hdcMem;
HBITMAP hbmp = NULL;
hdcMem = CreateCompatibleDC(NULL);
if (hdcMem)
{
hbmp = CreateCompatibleBitmap(hdcMem, psize->cx, psize->cy);
if (hbmp)
{
HBITMAP hbmpOld;
RECT rc;
// hbmp is monochrome
hbmpOld = SelectBitmap(hdcMem, hbmp);
rc.left = 0;
rc.top = 0;
rc.right = psize->cx;
rc.bottom = psize->cy;
DrawFrameControl(hdcMem, &rc, DFC_MENU, DFCS_MENUBULLET);
SelectBitmap(hdcMem, hbmpOld);
}
DeleteDC(hdcMem);
}
return hbmp;
}
/*----------------------------------------------------------
Purpose: Returns the resource ID string given the action
flag.
Returns: IDS_ value
Cond: --
*/
UINT PRIVATE GetActionText(
LPRA_PRIV ppriv)
{
UINT ids;
ASSERT(ppriv);
switch (ppriv->uAction)
{
case RAIA_TOOUT:
if (SI_NEW == ppriv->siInside.uState)
{
ids = IDS_STATE_Creates;
}
else
{
ids = IDS_STATE_Replaces;
}
break;
case RAIA_TOIN:
if (SI_NEW == ppriv->siOutside.uState)
{
ids = IDS_STATE_Creates;
}
else
{
ids = IDS_STATE_Replaces;
}
break;
case RAIA_SKIP:
// Can occur if the user explicitly wants to skip, or if
// one side is unavailable.
ids = IDS_STATE_Skip;
break;
case RAIA_CONFLICT: ids = IDS_STATE_Conflict; break;
case RAIA_MERGE: ids = IDS_STATE_Merge; break;
case RAIA_NOTHING: ids = IDS_STATE_Uptodate; break;
case RAIA_SOMETHING: ids = IDS_STATE_NeedToUpdate; break;
default: ids = 0; break;
}
return ids;
}
/*----------------------------------------------------------
Purpose: Repaint an item in the listbox
Returns: --
Cond: --
*/
void PRIVATE ListBox_RepaintItemNow(
HWND hwnd,
int iItem,
LPRECT prc, // Relative to individual entry rect. May be NULL
BOOL bEraseBk)
{
RECT rc;
RECT rcItem;
ListBox_GetItemRect(hwnd, iItem, &rcItem);
if (prc)
{
OffsetRect(prc, rcItem.left, rcItem.top);
IntersectRect(&rc, &rcItem, prc);
}
else
rc = rcItem;
InvalidateRect(hwnd, &rc, bEraseBk);
UpdateWindow(hwnd);
}
/*----------------------------------------------------------
Purpose: Send selection change notification
Returns:
Cond: --
*/
BOOL PRIVATE RecAct_SendSelChange(
LPRECACT this,
int isel)
{
NM_RECACT nm;
nm.iItem = isel;
nm.mask = 0;
if (isel != -1)
{
LPRA_ITEM pitem;
ListBox_GetText(this->hwndLB, isel, &pitem);
if (!pitem)
return FALSE;
nm.lParam = pitem->lParam;
nm.mask |= RAIF_LPARAM;
}
return !(BOOL)SendNotify(GetParent(this->hwnd), this->hwnd, RN_SELCHANGED, &nm.hdr);
}
/*----------------------------------------------------------
Purpose: Send an action change notification
Returns:
Cond: --
*/
BOOL PRIVATE RecAct_SendItemChange(
LPRECACT this,
int iEntry,
UINT uActionOld)
{
NM_RECACT nm;
nm.iItem = iEntry;
nm.mask = 0;
if (iEntry != -1)
{
LPRA_PRIV ppriv;
ListBox_GetText(this->hwndLB, iEntry, &ppriv);
if (!ppriv)
return FALSE;
nm.mask |= RAIF_LPARAM | RAIF_ACTION;
nm.lParam = ppriv->lParam;
nm.uAction = ppriv->uAction;
nm.uActionOld = uActionOld;
}
return !(BOOL)SendNotify(GetParent(this->hwnd), this->hwnd, RN_ITEMCHANGED, &nm.hdr);
}
/*----------------------------------------------------------
Purpose: Calculate the important coordinates that we want to save.
Returns: --
Cond: --
*/
void PRIVATE RecAct_CalcCoords(
LPRECACT this)
{
int xOutColumn;
ASSERT(this->cxSideItem != 0);
xOutColumn = this->cxItem - this->cxSideItem - g_cxMargin;
this->xAction = (RecAct_IsNoIcon(this) ? 0 : X_INCOLUMN) + this->cxSideItem;
this->cxAction = xOutColumn - this->xAction;
}
/*----------------------------------------------------------
Purpose: Create the action context menu
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE RecAct_CreateMenu(
LPRECACT this)
{
HMENU hmenu;
hmenu = CreatePopupMenu();
if (hmenu)
{
char sz[MAXSHORTLEN];
MENUITEMINFO mii;
int i;
// Add the help menu items now, since these will be standard
//
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
for (i = 0; i < ARRAYSIZE(c_rghmid); i++)
{
mii.wID = c_rghmid[i].idm;
mii.dwTypeData = SzFromIDS(c_rghmid[i].ids, sz, sizeof(sz));
InsertMenuItem(hmenu, i, TRUE, &mii);
}
this->hmenu = hmenu;
}
return hmenu != NULL;
}
/*----------------------------------------------------------
Purpose: Add the action menu items to the context menu
Returns: --
Cond: --
*/
void PRIVATE AddActionsToContextMenu(
HMENU hmenu,
UINT idmCheck, // menu item to checkmark
LPRA_PRIV ppriv)
{
MENUITEMINFO mii;
int i;
int cItems = ARRAYSIZE(c_rgramid);
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
mii.fType = MFT_OWNERDRAW;
mii.fState = MFS_ENABLED;
// Is merge supported?
if (IsFlagClear(ppriv->uStyle, RAIS_CANMERGE))
{
// No
--cItems;
}
for (i = 0; i < cItems; i++)
{
mii.wID = c_rgramid[i].idm;
mii.dwItemData = (DWORD)&c_rgramid[i];
InsertMenuItem(hmenu, i, TRUE, &mii);
}
// Add the separator
mii.fMask = MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
InsertMenuItem(hmenu, i, TRUE, &mii);
// Set the initial checkmark.
CheckMenuRadioItem(hmenu, IDM_ACTIONFIRST, IDM_ACTIONLAST, idmCheck,
MF_BYCOMMAND | MF_CHECKED);
#if 0
// Is merge supported?
if (IsFlagClear(ppriv->uStyle, RAIS_CANMERGE))
{
// No
mii.fMask = MIIM_STATE;
mii.fState = MFS_GRAYED | MFS_DISABLED;
SetMenuItemInfo(hmenu, IDM_MERGE, FALSE, &mii);
}
#endif
//tHACK
mii.fMask = MIIM_STATE;
mii.fState = MFS_GRAYED | MFS_DISABLED;
SetMenuItemInfo(hmenu, IDM_SKIP, FALSE, &mii);
// Is the file or its sync copy unavailable?
if (SI_UNAVAILABLE == ppriv->siInside.uState ||
SI_UNAVAILABLE == ppriv->siOutside.uState)
{
// Yes
mii.fMask = MIIM_STATE;
mii.fState = MFS_GRAYED | MFS_DISABLED;
SetMenuItemInfo(hmenu, IDM_TOIN, FALSE, &mii);
SetMenuItemInfo(hmenu, IDM_TOOUT, FALSE, &mii);
SetMenuItemInfo(hmenu, IDM_MERGE, FALSE, &mii);
}
// Is the file being created?
else if (ppriv->siInside.uState == SI_NEW ||
ppriv->siOutside.uState == SI_NEW)
{
// Yes; disable the replace-in-opposite direction
UINT idmDisable;
UINT idmChangeVerb;
if (ppriv->siInside.uState == SI_NEW)
{
idmDisable = IDM_TOIN;
idmChangeVerb = IDM_TOOUT;
i = IRAMID_CREATEOUT;
}
else
{
idmDisable = IDM_TOOUT;
idmChangeVerb = IDM_TOIN;
i = IRAMID_CREATEIN;
}
// Disable one of the directions
mii.fMask = MIIM_STATE;
mii.fState = MFS_GRAYED | MFS_DISABLED;
SetMenuItemInfo(hmenu, idmDisable, FALSE, &mii);
// Change the verb of the other direction
mii.fMask = MIIM_DATA;
mii.dwItemData = (DWORD)&c_rgramidCreates[i];
SetMenuItemInfo(hmenu, idmChangeVerb, FALSE, &mii);
}
}
/*----------------------------------------------------------
Purpose: Clear out the context menu
Returns: --
Cond: --
*/
void PRIVATE ResetContextMenu(
HMENU hmenu)
{
int cnt;
// If there is more than just the help items, remove them
// (but leave the help items)
//
cnt = GetMenuItemCount(hmenu);
if (cnt > ARRAYSIZE(c_rghmid))
{
int i;
cnt -= ARRAYSIZE(c_rghmid);
for (i = 0; i < cnt; i++)
{
DeleteMenu(hmenu, 0, MF_BYPOSITION);
}
}
}
/*----------------------------------------------------------
Purpose: Do the context menu
Returns: --
Cond: --
*/
void PRIVATE RecAct_DoContextMenu(
LPRECACT this,
int x, // in screen coords
int y,
int iEntry,
BOOL bHelpOnly) // TRUE: only show the help items
{
UINT idCmd;
if (this->hmenu)
{
LPRA_PRIV ppriv;
RECT rc;
int idmCheck;
UINT uActionOld;
// Only show help-portion of context menu?
if (bHelpOnly)
{
// Yes
ppriv = NULL;
}
else
{
// No
ListBox_GetText(this->hwndLB, iEntry, &ppriv);
// Determine if this is a help-context menu only.
// It is if this is a folder-item or if there is no action
// to take.
//
ASSERT(ppriv->uAction < ARRAYSIZE(c_mpraiaidmMenu));
idmCheck = c_mpraiaidmMenu[ppriv->uAction];
// Build the context menu
//
if (IsFlagClear(ppriv->uStyle, RAIS_FOLDER) && idmCheck != 0)
{
AddActionsToContextMenu(this->hmenu, idmCheck, ppriv);
}
}
// Show context menu
//
idCmd = TrackPopupMenu(this->hmenu,
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
x, y, 0, this->hwnd, NULL);
// Clear menu
//
ResetContextMenu(this->hmenu);
if (ppriv)
{
// Save the old action
uActionOld = ppriv->uAction;
}
// Act on whatever the user chose
switch (idCmd)
{
case IDM_TOOUT:
ppriv->uAction = RAIA_TOOUT;
break;
case IDM_TOIN:
ppriv->uAction = RAIA_TOIN;
break;
case IDM_SKIP:
ppriv->uAction = RAIA_SKIP;
break;
case IDM_MERGE:
ppriv->uAction = RAIA_MERGE;
break;
// tHACK case IDM_WHATSTHIS:
// WinHelp(this->hwnd, c_szWinHelpFile, HELP_CONTEXTPOPUP, IDH_BFC_UPDATE_SCREEN);
// return; // Return now
default:
return; // Return now
}
// Repaint action portion of entry
ppriv->cx = RECOMPUTE;
rc = ppriv->rgdobj[IDOBJ_ACTION].rcBounding;
ListBox_RepaintItemNow(this->hwndLB, iEntry, &rc, TRUE);
// Send a notify message
ASSERT(NULL != ppriv); // uActionOld should be valid
RecAct_SendItemChange(this, iEntry, uActionOld);
}
}
/*----------------------------------------------------------
Purpose: Create the windows for this control
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE RecAct_CreateWindows(
LPRECACT this,
CREATESTRUCT FAR * lpcs)
{
HWND hwnd = this->hwnd;
HWND hwndLB = NULL;
RECT rc;
int cxEdge = GetSystemMetrics(SM_CXEDGE);
int cyEdge = GetSystemMetrics(SM_CYEDGE);
// Create listbox
hwndLB = CreateWindowEx(
0,
"listbox",
"",
WS_CHILD | WS_CLIPSIBLINGS | LBS_SORT | LBS_OWNERDRAWVARIABLE |
WS_VSCROLL | WS_TABSTOP | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
LBS_NOTIFY,
0, 0, lpcs->cx, lpcs->cy,
hwnd,
NULL,
lpcs->hInstance,
0L);
if (!hwndLB)
return FALSE;
SetWindowFont(hwndLB, this->hfont, FALSE);
this->hwndLB = hwndLB;
// Determine layout of window
GetClientRect(hwnd, &rc);
InflateRect(&rc, -cxEdge, -cyEdge);
SetWindowPos(hwndLB, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOZORDER);
GetClientRect(hwndLB, &rc);
this->cxItem = rc.right - rc.left;
return TRUE;
}
/*----------------------------------------------------------
Purpose: Set the colors of the control
Returns: --
Cond: --
*/
void PRIVATE RecAct_SetColors(
LPRECACT this)
{
int cr;
if (IsFlagClear(this->lStyle, RAS_SINGLEITEM))
{
cr = COLOR_WINDOW;
}
else
{
cr = COLOR_3DFACE;
}
this->clrBkgnd = GetSysColor(cr);
if (this->hbrBkgnd)
DeleteBrush(this->hbrBkgnd);
this->hbrBkgnd = CreateSolidBrush(this->clrBkgnd);
}
/*----------------------------------------------------------
Purpose: Creates an imagelist of the action images
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE CreateImageList(
HIMAGELIST * phiml,
HDC hdc,
UINT idb,
int cxBmp,
int cyBmp,
int cImage)
{
BOOL bRet;
HIMAGELIST himl;
himl = ImageList_Create(cxBmp, cyBmp, TRUE, cImage, 1);
if (himl)
{
COLORREF clrMask;
HBITMAP hbm;
hbm = LoadBitmap(vhinstCur, MAKEINTRESOURCE(idb));
ASSERT(hbm);
if (hbm)
{
HDC hdcMem = CreateCompatibleDC(hdc);
if (hdcMem)
{
HBITMAP hbmSav = SelectBitmap(hdcMem, hbm);
clrMask = GetPixel(hdcMem, 0, 0);
SelectBitmap(hdcMem, hbmSav);
bRet = (0 == ImageList_AddMasked(himl, hbm, clrMask));
DeleteDC(hdcMem);
}
else
bRet = FALSE;
DeleteBitmap(hbm);
}
else
bRet = FALSE;
}
else
bRet = FALSE;
*phiml = himl;
return bRet;
}
/*----------------------------------------------------------
Purpose: WM_CREATE handler
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE RecAct_OnCreate(
LPRECACT this,
CREATESTRUCT FAR * lpcs)
{
BOOL bRet = FALSE;
HWND hwnd = this->hwnd;
HDC hdc;
TEXTMETRIC tm;
RECT rcT;
LOGFONT lf;
this->lStyle = GetWindowLong(hwnd, GWL_STYLE);
RecAct_SetColors(this);
// Determine some font things
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
this->hfont = CreateFontIndirect(&lf);
// This window is registered with the CS_OWNDC flag
this->hdcOwn = GetDC(hwnd);
ASSERT(this->hdcOwn);
hdc = this->hdcOwn;
SelectFont(hdc, this->hfont);
GetTextMetrics(hdc, &tm);
this->cyText = tm.tmHeight;
// Calculate text extent for sideitems (use the listbox font)
//
SetRectFromExtent(hdc, &rcT, c_szEllipses);
this->cxEllipses = rcT.right - rcT.left;
SetRectFromExtent(hdc, &rcT, c_szDateDummy);
this->cxSideItem = (rcT.right - rcT.left) + 2*g_cxMargin;
// Create windows used by control
if (RecAct_CreateWindows(this, lpcs))
{
RecAct_CalcCoords(this);
this->lpfnLBProc = SubclassWindow(this->hwndLB, RecActLB_LBProc);
// Get the system imagelist cache
//
this->himlCache = ImageList_Create(g_cxIcon, g_cyIcon, TRUE, 8, 8);
if (this->himlCache)
{
if (CreateImageList(&this->himlAction, hdc, IDB_ACTIONS,
CX_ACTIONBMP, CY_ACTIONBMP, 8))
{
SIZE size;
// Get some metrics
this->cxMenuCheck = GetSystemMetrics(SM_CXMENUCHECK);
this->cyMenuCheck = GetSystemMetrics(SM_CYMENUCHECK);
size.cx = this->cxMenuCheck;
size.cy = this->cyMenuCheck;
this->hbmpBullet = CreateBulletBitmap(&size);
if (this->hbmpBullet)
{
bRet = RecAct_CreateMenu(this);
}
}
}
}
return bRet;
}
/*----------------------------------------------------------
Purpose: WM_DESTROY Handler
Returns: --
Cond: --
*/
void PRIVATE RecAct_OnDestroy(
LPRECACT this)
{
if (this->himlCache)
{
ImageList_Destroy(this->himlCache);
this->himlCache = NULL;
}
if (this->himlAction)
{
ImageList_Destroy(this->himlAction);
this->himlAction = NULL;
}
if (this->hbmpBullet)
{
DeleteBitmap(this->hbmpBullet);
this->hbmpBullet = NULL;
}
if (this->hmenu)
{
DestroyMenu(this->hmenu);
this->hmenu = NULL;
}
if (this->hbrBkgnd)
DeleteBrush(this->hbrBkgnd);
if (this->hfont)
DeleteFont(this->hfont);
}
/*----------------------------------------------------------
Purpose: WM_COMMAND Handler
Returns: --
Cond: --
*/
VOID PRIVATE RecAct_OnCommand(
LPRECACT this,
int id,
HWND hwndCtl,
UINT uNotifyCode)
{
if (hwndCtl == this->hwndLB)
{
switch (uNotifyCode)
{
case LBN_SELCHANGE:
break;
}
}
}
/*----------------------------------------------------------
Purpose: WM_NOTIFY handler
Returns: varies
Cond: --
*/
LRESULT PRIVATE RecAct_OnNotify(
LPRECACT this,
int idFrom,
NMHDR FAR * lpnmhdr)
{
LRESULT lRet = 0;
switch (lpnmhdr->code)
{
case HDN_BEGINTRACK:
lRet = TRUE; // prevent tracking
break;
default:
break;
}
return lRet;
}
/*----------------------------------------------------------
Purpose: WM_CONTEXTMENU handler
Returns: --
Cond: --
*/
void PRIVATE RecAct_OnContextMenu(
LPRECACT this,
HWND hwnd,
int x,
int y)
{
if (hwnd == this->hwndLB)
{
POINT pt;
int iHitEntry;
BOOL bHelpOnly = TRUE;
pt.x = x;
pt.y = y;
ScreenToClient(hwnd, &pt);
iHitEntry = (pt.y / ListBox_GetItemHeight(hwnd, 0)) + ListBox_GetTopIndex(hwnd);
ASSERT(iHitEntry >= 0);
if (iHitEntry < ListBox_GetCount(hwnd))
{
ListBox_SetCurSel(hwnd, iHitEntry);
ListBox_RepaintItemNow(hwnd, iHitEntry, NULL, FALSE);
bHelpOnly = FALSE;
}
// Bring up the context menu for the listbox
RecAct_DoContextMenu(this, x, y, iHitEntry, bHelpOnly);
}
}
/*----------------------------------------------------------
Purpose: Calculate the rectangle boundary of a sideitem
Returns: calculated rect
Cond: --
*/
void PRIVATE RecAct_CalcSideItemRect(
LPRECACT this,
int nSide, // SIDE_INSIDE or SIDE_OUTSIDE
LPRECT prcOut)
{
int x;
int y = g_cyIconMargin*2;
if (SIDE_INSIDE == nSide)
{
x = g_cxMargin;
if ( !RecAct_IsNoIcon(this) )
x += X_INCOLUMN;
}
else
{
ASSERT(SIDE_OUTSIDE == nSide);
x = this->cxItem - this->cxSideItem - g_cxMargin;
}
prcOut->left = x;
prcOut->top = y;
prcOut->right = x + this->cxSideItem;
prcOut->bottom = y + (this->cyText * 3);
}
/*----------------------------------------------------------
Purpose: Draw a reconciliation listbox entry
Returns: --
Cond: --
*/
void PRIVATE RecAct_RecomputeItemMetrics(
LPRECACT this,
LPRA_PRIV ppriv)
{
HDC hdc = this->hdcOwn;
LPDOBJ pdobj = ppriv->rgdobj;
RECT rcT;
RECT rcUnion;
char szIDS[MAXBUFLEN];
UINT ids;
int cyText = this->cyText;
POINT pt;
// Compute the metrics and dimensions of each of the draw objects
// and store back into the item.
// File icon and label
pt.x = 0;
pt.y = 0;
ComputeImageRects(FIGetDisplayName(ppriv->pfi), hdc, &pt,
&pdobj->rcBounding, &pdobj->rcLabel, g_cxIcon, g_cyIcon,
g_cxIconSpacing, cyText);
pdobj->uKind = DOK_IMAGE;
pdobj->lpvObject = FIGetDisplayName(ppriv->pfi);
pdobj->uFlags = DOF_DIFFER | DOF_CENTER;
if (RecAct_IsNoIcon(this))
SetFlag(pdobj->uFlags, DOF_NODRAW);
pdobj->x = pt.x;
pdobj->y = pt.y;
pdobj->himl = this->himlCache;
pdobj->iImage = (UINT)ppriv->pfi->lParam;
rcUnion = pdobj->rcBounding;
// Sideitem Info (Inside Briefcase)
RecAct_CalcSideItemRect(this, SIDE_INSIDE, &rcT);
pdobj++;
pdobj->uKind = DOK_SIDEITEM;
pdobj->lpvObject = &ppriv->siInside;
pdobj->uFlags = DOF_LEFT;
pdobj->x = rcT.left;
pdobj->y = rcT.top;
pdobj->rcClip = rcT;
pdobj->rcBounding = rcT;
// Sideitem Info (Outside Briefcase)
RecAct_CalcSideItemRect(this, SIDE_OUTSIDE, &rcT);
pdobj++;
pdobj->uKind = DOK_SIDEITEM;
pdobj->lpvObject = &ppriv->siOutside;
pdobj->uFlags = DOF_LEFT;
pdobj->x = rcT.left;
pdobj->y = rcT.top;
pdobj->rcClip = rcT;
pdobj->rcBounding = rcT;
UnionRect(&rcUnion, &rcUnion, &rcT);
// Action image
ASSERT(ppriv->uAction <= ARRAYSIZE(c_mpraiaiImage));
pdobj++;
ids = GetActionText(ppriv);
pt.x = this->xAction;
pt.y = 0;
ComputeImageRects(SzFromIDS(ids, szIDS, sizeof(szIDS)), hdc, &pt,
&pdobj->rcBounding, &pdobj->rcLabel, CX_ACTIONBMP, CY_ACTIONBMP,
this->cxAction, cyText);
pdobj->uKind = DOK_IMAGE;
pdobj->lpvObject = (LPVOID)ids;
pdobj->uFlags = DOF_CENTER | DOF_USEIDS;
if (!RecAct_IsNoIcon(this))
SetFlag(pdobj->uFlags, DOF_IGNORESEL);
pdobj->x = pt.x;
pdobj->y = pt.y;
pdobj->himl = this->himlAction;
pdobj->iImage = c_mpraiaiImage[ppriv->uAction];
UnionRect(&rcUnion, &rcUnion, &pdobj->rcBounding);
// Set the bounding rect of this item.
ppriv->cx = rcUnion.right - rcUnion.left;
ppriv->cy = max((rcUnion.bottom - rcUnion.top), g_cyIconSpacing);
}
/*----------------------------------------------------------
Purpose: WM_MEASUREITEM handler
Returns: --
Cond: --
*/
void PRIVATE RecAct_OnMeasureItem(
LPRECACT this,
LPMEASUREITEMSTRUCT lpmis)
{
HDC hdc = this->hdcOwn;
switch (lpmis->CtlType)
{
case ODT_LISTBOX: {
LPRA_PRIV ppriv = (LPRA_PRIV)lpmis->itemData;
// Recompute item metrics?
if (RECOMPUTE == ppriv->cx)
{
RecAct_RecomputeItemMetrics(this, ppriv); // Yes
}
lpmis->itemHeight = ppriv->cy;
}
break;
case ODT_MENU:
{
int i;
int cxMac = 0;
RECT rc;
char sz[MAXBUFLEN];
// Calculate based on font and image dimensions.
//
SelectFont(hdc, this->hfont);
cxMac = 0;
for (i = 0; i < ARRAYSIZE(c_rgramid); i++)
{
SzFromIDS(c_rgramid[i].ids, sz, sizeof(sz));
SetRectFromExtent(hdc, &rc, sz);
cxMac = max(cxMac,
g_cxMargin + CX_ACTIONBMP + g_cxMargin +
(rc.right-rc.left) + g_cxMargin);
}
lpmis->itemHeight = max(this->cyText, CY_ACTIONBMP);
lpmis->itemWidth = cxMac;
}
break;
}
}
/*----------------------------------------------------------
Purpose: Draw a reconciliation listbox entry
Returns: --
Cond: --
*/
void PRIVATE RecAct_DrawLBItem(
LPRECACT this,
const DRAWITEMSTRUCT FAR * lpcdis)
{
LPRA_PRIV ppriv = (LPRA_PRIV)lpcdis->itemData;
HDC hdc = lpcdis->hDC;
RECT rc = lpcdis->rcItem;
POINT ptSav;
LPDOBJ pdobj;
UINT cdobjs;
if (!ppriv)
{
// Empty listbox and we're getting the focus
return;
}
SetBkMode(hdc, TRANSPARENT); // required for Shell_DrawText
SetViewportOrgEx(hdc, rc.left, rc.top, &ptSav);
// The Chicago-look mandates that icon and filename are selected,
// the rest of the entry is normal. Yuk.
// Recompute item metrics?
if (RECOMPUTE == ppriv->cx)
{
RecAct_RecomputeItemMetrics(this, ppriv); // Yes
}
// Do we need to redraw everything?
if (IsFlagSet(lpcdis->itemAction, ODA_DRAWENTIRE))
{
// Yes
cdobjs = ARRAYSIZE(ppriv->rgdobj);
pdobj = ppriv->rgdobj;
}
else
{
// No; should we even draw the file icon or action icon?
if (lpcdis->itemAction & (ODA_FOCUS | ODA_SELECT))
{
cdobjs = 1; // Yes
// Focus rect on file icon?
if (!RecAct_IsNoIcon(this))
pdobj = ppriv->rgdobj;
else
pdobj = &ppriv->rgdobj[IDOBJ_ACTION];
}
else
{
cdobjs = 0; // No
pdobj = ppriv->rgdobj;
}
}
Dobj_Draw(hdc, pdobj, cdobjs, lpcdis->itemState, this->cxEllipses, this->cyText,
this->clrBkgnd);
// Clean up
//
SetViewportOrgEx(hdc, ptSav.x, ptSav.y, NULL);
}
/*----------------------------------------------------------
Purpose: Draw an action menu item
Returns: --
Cond: --
*/
void PRIVATE RecAct_DrawMenuItem(
LPRECACT this,
const DRAWITEMSTRUCT FAR * lpcdis)
{
LPRAMID pramid = (LPRAMID)lpcdis->itemData;
HDC hdc = lpcdis->hDC;
RECT rc = lpcdis->rcItem;
DOBJ dobj;
LPDOBJ pdobj;
POINT ptSav;
MENUITEMINFO mii;
int cx;
int cy;
UINT uFlags;
UINT uFlagsChecked;
ASSERT(pramid);
if (lpcdis->itemID == -1)
return;
SetViewportOrgEx(hdc, rc.left, rc.top, &ptSav);
OffsetRect(&rc, -rc.left, -rc.top);
cx = rc.right - rc.left;
cy = rc.bottom - rc.top;
// Get the menu state
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_CHECKMARKS;
GetMenuItemInfo(this->hmenu, lpcdis->itemID, FALSE, &mii);
uFlagsChecked = IsFlagClear(mii.fState, MFS_CHECKED) ? DOF_NODRAW : 0;
uFlags = DOF_DIFFER | DOF_MENU | DOF_USEIDS;
if (IsFlagSet(mii.fState, MFS_GRAYED))
SetFlag(uFlags, DOF_DISABLED);
// Build the array of DObjs that we want to draw.
// Action image
pdobj = &dobj;
pdobj->uKind = DOK_IMAGE;
pdobj->lpvObject = (LPVOID)pramid->ids;
pdobj->himl = this->himlAction;
pdobj->iImage = pramid->iImage;
pdobj->uFlags = uFlags;
pdobj->x = g_cxMargin;
pdobj->y = (cy - CY_ACTIONBMP) / 2;
pdobj->rcLabel.left = 0;
pdobj->rcLabel.right = cx;
pdobj->rcLabel.top = 0;
pdobj->rcLabel.bottom = cy;
// Draw the entry...
//
Dobj_Draw(hdc, &dobj, 1, lpcdis->itemState, 0, this->cyText, this->clrBkgnd);
// Clean up
//
SetViewportOrgEx(hdc, ptSav.x, ptSav.y, NULL);
}
/*----------------------------------------------------------
Purpose: WM_DRAWITEM handler
Returns: --
Cond: --
*/
void PRIVATE RecAct_OnDrawItem(
LPRECACT this,
const DRAWITEMSTRUCT FAR * lpcdis)
{
switch (lpcdis->CtlType)
{
case ODT_LISTBOX:
RecAct_DrawLBItem(this, lpcdis);
break;
case ODT_MENU:
RecAct_DrawMenuItem(this, lpcdis);
break;
}
}
/*----------------------------------------------------------
Purpose: WM_COMPAREITEM handler
Returns: -1 (item 1 precedes item 2), 0 (equal), 1 (item 2 precedes item 1)
Cond: --
*/
int PRIVATE RecAct_OnCompareItem(
LPRECACT this,
const COMPAREITEMSTRUCT FAR * lpcis)
{
LPRA_PRIV ppriv1 = (LPRA_PRIV)lpcis->itemData1;
LPRA_PRIV ppriv2 = (LPRA_PRIV)lpcis->itemData2;
// We sort based on name of file
//
return lstrcmpi(FIGetPath(ppriv1->pfi), FIGetPath(ppriv2->pfi));
}
/*----------------------------------------------------------
Purpose: WM_DELETEITEM handler
Returns: --
Cond: --
*/
void RecAct_OnDeleteLBItem(
LPRECACT this,
const DELETEITEMSTRUCT FAR * lpcdis)
{
switch (lpcdis->CtlType)
{
case ODT_LISTBOX:
{
LPRA_PRIV ppriv = (LPRA_PRIV)lpcdis->itemData;
ASSERT(ppriv);
if (ppriv)
{
FIFree(ppriv->pfi);
GFree(ppriv->siInside.pszDir);
GFree(ppriv->siOutside.pszDir);
GFree(ppriv);
}
}
break;
}
}
/*----------------------------------------------------------
Purpose: WM_CTLCOLORLISTBOX handler
Returns: --
Cond: --
*/
HBRUSH PRIVATE RecAct_OnCtlColorListBox(
LPRECACT this,
HDC hdc,
HWND hwndLB,
int nType)
{
return this->hbrBkgnd;
}
/*----------------------------------------------------------
Purpose: WM_PAINT handler
Returns: --
Cond: --
*/
void RecAct_OnPaint(
LPRECACT this)
{
HWND hwnd = this->hwnd;
PAINTSTRUCT ps;
RECT rc;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
if (IsFlagSet(this->lStyle, RAS_SINGLEITEM))
{
DrawEdge(hdc, &rc, BDR_SUNKENINNER, BF_TOPLEFT);
DrawEdge(hdc, &rc, BDR_SUNKENOUTER, BF_BOTTOMRIGHT);
}
else
{
DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
}
EndPaint(hwnd, &ps);
}
/*----------------------------------------------------------
Purpose: WM_SETFONT handler
Returns: --
Cond: --
*/
void RecAct_OnSetFont(
LPRECACT this,
HFONT hfont,
BOOL bRedraw)
{
this->hfont = hfont;
FORWARD_WM_SETFONT(this->hwnd, hfont, bRedraw, RecAct_DefProc);
}
/*----------------------------------------------------------
Purpose: WM_SETFOCUS handler
Returns: --
Cond: --
*/
void RecAct_OnSetFocus(
LPRECACT this,
HWND hwndOldFocus)
{
SetFocus(this->hwndLB);
}
/*----------------------------------------------------------
Purpose: WM_SYSCOLORCHANGE handler
Returns: --
Cond: --
*/
void RecAct_OnSysColorChange(
LPRECACT this)
{
RecAct_SetColors(this);
InvalidateRect(this->hwnd, NULL, TRUE);
}
/*----------------------------------------------------------
Purpose: Insert item
Returns: index
Cond: --
*/
int PRIVATE RecAct_OnInsertItem(
LPRECACT this,
const LPRA_ITEM pitem)
{
HWND hwndLB = this->hwndLB;
LPRA_PRIV pprivNew;
char szPath[MAXPATHLEN];
int iRet = -1;
int iItem = LB_ERR;
ASSERT(pitem);
ASSERT(pitem->siInside.pszDir);
ASSERT(pitem->siOutside.pszDir);
ASSERT(pitem->pszName);
pprivNew = GAlloc(sizeof(*pprivNew));
if (pprivNew)
{
SetWindowRedraw(hwndLB, FALSE);
// Fill the prerequisite fields first
//
pprivNew->uStyle = pitem->uStyle;
pprivNew->uAction = pitem->uAction;
// Set the fileinfo stuff and large icon system-cache index.
// If we can't get the fileinfo of the inside file, get the outside
// file. If neither can be found, then we fail
//
lstrcpy(szPath, pitem->siInside.pszDir);
if (IsFlagClear(pitem->uStyle, RAIS_FOLDER))
PathAppend(szPath, pitem->pszName);
PathMakePresentable(szPath);
if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON)))
{
// Try the outside file
//
lstrcpy(szPath, pitem->siOutside.pszDir);
if (IsFlagClear(pitem->uStyle, RAIS_FOLDER))
PathAppend(szPath, pitem->pszName);
PathMakePresentable(szPath);
if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON)))
{
// Don't try to touch the file
if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON | FIF_DONTTOUCH)))
goto Insert_Cleanup;
}
}
ASSERT(pprivNew->pfi);
pprivNew->pfi->lParam = (LPARAM)ImageList_AddIcon(this->himlCache, pprivNew->pfi->hicon);
// Fill in the rest of the fields
//
lstrcpy(szPath, pitem->siInside.pszDir);
if (IsFlagSet(pitem->uStyle, RAIS_FOLDER))
PathRemoveFileSpec(szPath);
PathMakePresentable(szPath);
if (!GSetString(&pprivNew->siInside.pszDir, szPath))
goto Insert_Cleanup;
pprivNew->siInside.uState = pitem->siInside.uState;
pprivNew->siInside.fs = pitem->siInside.fs;
lstrcpy(szPath, pitem->siOutside.pszDir);
if (IsFlagSet(pitem->uStyle, RAIS_FOLDER))
PathRemoveFileSpec(szPath);
PathMakePresentable(szPath);
if (!GSetString(&pprivNew->siOutside.pszDir, szPath))
goto Insert_Cleanup;
pprivNew->siOutside.uState = pitem->siOutside.uState;
pprivNew->siOutside.fs = pitem->siOutside.fs;
pprivNew->lParam = pitem->lParam;
pprivNew->cx = RECOMPUTE;
// We know we're doing a redundant sorted add if the element
// needs to be inserted at the end of the list, but who cares.
//
if (pitem->iItem >= RecAct_GetCount(this))
iItem = ListBox_AddString(hwndLB, pprivNew);
else
iItem = ListBox_InsertString(hwndLB, pitem->iItem, pprivNew);
if (iItem == LB_ERR)
goto Insert_Cleanup;
SetWindowRedraw(hwndLB, TRUE);
iRet = iItem;
}
goto Insert_End;
Insert_Cleanup:
// Have DeleteString handler clean up field allocations
// of pitem.
//
if (iItem != LB_ERR)
ListBox_DeleteString(hwndLB, iItem);
else
{
FIFree(pprivNew->pfi);
GFree(pprivNew);
}
SetWindowRedraw(hwndLB, TRUE);
Insert_End:
return iRet;
}
/*----------------------------------------------------------
Purpose: Delete item
Returns: count of items left
Cond: --
*/
int PRIVATE RecAct_OnDeleteItem(
LPRECACT this,
int i)
{
HWND hwndLB = this->hwndLB;
return ListBox_DeleteString(hwndLB, i);
}
/*----------------------------------------------------------
Purpose: Delete all items
Returns: TRUE
Cond: --
*/
BOOL PRIVATE RecAct_OnDeleteAllItems(
LPRECACT this)
{
ListBox_ResetContent(this->hwndLB);
return TRUE;
}
/*----------------------------------------------------------
Purpose: Get item
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE RecAct_OnGetItem(
LPRECACT this,
LPRA_ITEM pitem)
{
LPRA_PRIV ppriv;
HWND hwndLB = this->hwndLB;
UINT uMask;
int iItem;
if (!pitem)
return FALSE;
iItem = pitem->iItem;
uMask = pitem->mask;
ListBox_GetText(hwndLB, iItem, &ppriv);
if (uMask & RAIF_ACTION)
pitem->uAction = ppriv->uAction;
if (uMask & RAIF_NAME)
pitem->pszName = FIGetPath(ppriv->pfi);
if (uMask & RAIF_STYLE)
pitem->uStyle = ppriv->uStyle;
if (uMask & RAIF_INSIDE)
pitem->siInside = ppriv->siInside;
if (uMask & RAIF_OUTSIDE)
pitem->siOutside = ppriv->siOutside;
if (uMask & RAIF_LPARAM)
pitem->lParam = ppriv->lParam;
return TRUE;
}
/*----------------------------------------------------------
Purpose: Set item
Returns: TRUE on success
Cond: --
*/
BOOL PRIVATE RecAct_OnSetItem(
LPRECACT this,
LPRA_ITEM pitem)
{
LPRA_PRIV ppriv;
HWND hwndLB = this->hwndLB;
UINT uMask;
int iItem;
if (!pitem)
return FALSE;
uMask = pitem->mask;
iItem = pitem->iItem;
ListBox_GetText(hwndLB, iItem, &ppriv);
if (uMask & RAIF_ACTION)
ppriv->uAction = pitem->uAction;
if (uMask & RAIF_STYLE)
ppriv->uStyle = pitem->uStyle;
if (uMask & RAIF_NAME)
{
if (!FISetPath(&ppriv->pfi, pitem->pszName, FIF_ICON))
return FALSE;
ppriv->pfi->lParam = (LPARAM)ImageList_AddIcon(this->himlCache, ppriv->pfi->hicon);
}
if (uMask & RAIF_INSIDE)
{
if (!GSetString(&ppriv->siInside.pszDir, pitem->siInside.pszDir))
return FALSE;
ppriv->siInside.uState = pitem->siInside.uState;
ppriv->siInside.fs = pitem->siInside.fs;
}
if (uMask & RAIF_OUTSIDE)
{
if (!GSetString(&ppriv->siOutside.pszDir, pitem->siOutside.pszDir))
return FALSE;
ppriv->siOutside.uState = pitem->siOutside.uState;
ppriv->siOutside.fs = pitem->siOutside.fs;
}
if (uMask & RAIF_LPARAM)
ppriv->lParam = pitem->lParam;
return TRUE;
}
/*----------------------------------------------------------
Purpose: Get the current selection
Returns: index
Cond: --
*/
int PRIVATE RecAct_OnGetCurSel(
LPRECACT this)
{
return ListBox_GetCurSel(this->hwndLB);
}
/*----------------------------------------------------------
Purpose: Set the current selection
Returns: --
Cond: --
*/
int PRIVATE RecAct_OnSetCurSel(
LPRECACT this,
int i)
{
int iRet = ListBox_SetCurSel(this->hwndLB, i);
if (iRet != LB_ERR)
RecAct_SendSelChange(this, i);
return iRet;
}
/*----------------------------------------------------------
Purpose: Find an item
Returns: TRUE on success
Cond: --
*/
int PRIVATE RecAct_OnFindItem(
LPRECACT this,
int iStart,
const RA_FINDITEM FAR * prafi)
{
HWND hwndLB = this->hwndLB;
UINT uMask = prafi->flags;
LPRA_PRIV ppriv;
BOOL bPass;
int i;
int cItems = ListBox_GetCount(hwndLB);
for (i = iStart+1; i < cItems; i++)
{
bPass = TRUE; // assume we pass
ListBox_GetText(hwndLB, i, &ppriv);
if (uMask & RAFI_NAME &&
!IsSzEqual(FIGetPath(ppriv->pfi), prafi->psz))
bPass = FALSE;
if (uMask & RAFI_ACTION && ppriv->uAction != prafi->uAction)
bPass = FALSE;
if (uMask & RAFI_LPARAM && ppriv->lParam != prafi->lParam)
bPass = FALSE;
if (bPass)
break; // found it
}
return i == cItems ? -1 : i;
}
///////////////////////////////////////////////////// EXPORTED FUNCTIONS
/*----------------------------------------------------------
Purpose: RecAct window proc
Returns: varies
Cond: --
*/
LRESULT CALLBACK RecAct_WndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
LPRECACT this = RecAct_GetPtr(hwnd);
if (this == NULL)
{
if (msg == WM_NCCREATE)
{
this = GAlloc(sizeof(*this));
ASSERT(this);
if (!this)
return 0L; // OOM failure
this->hwnd = hwnd;
RecAct_SetPtr(hwnd, this);
}
else
{
return RecAct_DefProc(hwnd, msg, wParam, lParam);
}
}
if (msg == WM_NCDESTROY)
{
GFree(this);
RecAct_SetPtr(hwnd, NULL);
}
switch (msg)
{
HANDLE_MSG(this, WM_CREATE, RecAct_OnCreate);
HANDLE_MSG(this, WM_DESTROY, RecAct_OnDestroy);
HANDLE_MSG(this, WM_SETFONT, RecAct_OnSetFont);
HANDLE_MSG(this, WM_COMMAND, RecAct_OnCommand);
HANDLE_MSG(this, WM_NOTIFY, RecAct_OnNotify);
HANDLE_MSG(this, WM_MEASUREITEM, RecAct_OnMeasureItem);
HANDLE_MSG(this, WM_DRAWITEM, RecAct_OnDrawItem);
HANDLE_MSG(this, WM_COMPAREITEM, RecAct_OnCompareItem);
HANDLE_MSG(this, WM_DELETEITEM, RecAct_OnDeleteLBItem);
HANDLE_MSG(this, WM_CONTEXTMENU, RecAct_OnContextMenu);
HANDLE_MSG(this, WM_SETFOCUS, RecAct_OnSetFocus);
HANDLE_MSG(this, WM_CTLCOLORLISTBOX, RecAct_OnCtlColorListBox);
HANDLE_MSG(this, WM_PAINT, RecAct_OnPaint);
HANDLE_MSG(this, WM_SYSCOLORCHANGE, RecAct_OnSysColorChange);
case RAM_GETITEMCOUNT:
return (LRESULT)RecAct_GetCount(this);
case RAM_GETITEM:
return (LRESULT)RecAct_OnGetItem(this, (LPRA_ITEM)lParam);
case RAM_SETITEM:
return (LRESULT)RecAct_OnSetItem(this, (const LPRA_ITEM)lParam);
case RAM_INSERTITEM:
return (LRESULT)RecAct_OnInsertItem(this, (const LPRA_ITEM)lParam);
case RAM_DELETEITEM:
return (LRESULT)RecAct_OnDeleteItem(this, (int)wParam);
case RAM_DELETEALLITEMS:
return (LRESULT)RecAct_OnDeleteAllItems(this);
case RAM_GETCURSEL:
return (LRESULT)RecAct_OnGetCurSel(this);
case RAM_SETCURSEL:
return (LRESULT)RecAct_OnSetCurSel(this, (int)wParam);
case RAM_FINDITEM:
return (LRESULT)RecAct_OnFindItem(this, (int)wParam, (const RA_FINDITEM FAR *)lParam);
case RAM_REFRESH:
RedrawWindow(this->hwndLB, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
default:
return RecAct_DefProc(hwnd, msg, wParam, lParam);
}
}
///////////////////////////////////////////////////// PUBLIC FUNCTIONS
/*----------------------------------------------------------
Purpose: Initialize the reconciliation-action window class
Returns: TRUE on success
Cond: --
*/
BOOL PUBLIC RecAct_Init(HINSTANCE hinst)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_DBLCLKS | CS_OWNDC;
wc.lpfnWndProc = RecAct_WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LPRECACT);
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground= NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName= WC_RECACT;
wc.hIconSm = NULL;
return (RegisterClassEx(&wc) != 0);
}
/*----------------------------------------------------------
Purpose: Clean up RecAct window class
Returns: --
Cond: --
*/
void PUBLIC RecAct_Term(
HINSTANCE hinst)
{
UnregisterClass(WC_RECACT, hinst);
}
/*----------------------------------------------------------
Purpose: Special sub-class listbox proc
Returns: varies
Cond: --
*/
LRESULT _export CALLBACK RecActLB_LBProc(
HWND hwnd, // window handle
UINT msg, // window message
WPARAM wparam, // varies
LPARAM lparam) // varies
{
LRESULT lRet;
LPRECACT lpra = NULL;
// Get the instance data for the control
lpra = RecAct_GetPtr(GetParent(hwnd));
ASSERT(lpra);
switch (msg)
{
default:
lRet = RecActLB_DefProc(lpra->lpfnLBProc, hwnd, msg, wparam, lparam);
break;
}
return lRet;
}