|
|
/*
* pickicon - Icon picker */
#include "stdafx.h"
#include "pickicon.h"
#include "windowsx.h"
#include "commdlg.h"
#include "resource.h"
#include "util.h"
#define cA(a) (sizeof(a)/sizeof(a[0]))
typedef TCHAR TCH;
typedef struct COFN { /* common open file name */ OPENFILENAME ofn; /* The thing COMMDLG wants */ TCH tsz[MAX_PATH]; /* Where we build the name */ TCH tszFilter[100]; /* File open/save filter */ } COFN, *PCOFN;
/*****************************************************************************
* * InitOpenFileName * * Initialize a COFN structure. * *****************************************************************************/
void PASCAL InitOpenFileName(HWND hwnd, PCOFN pcofn, UINT ids, LPCTSTR pszInit) { int itchMax; TCH tch;
ZeroMemory(&pcofn->ofn, sizeof(pcofn->ofn)); pcofn->ofn.lStructSize |= sizeof(pcofn->ofn); pcofn->ofn.hwndOwner = hwnd; pcofn->ofn.lpstrFilter = pcofn->tszFilter; pcofn->ofn.lpstrFile = pcofn->tsz; pcofn->ofn.nMaxFile = MAX_PATH; pcofn->ofn.Flags |= (OFN_HIDEREADONLY | OFN_NOCHANGEDIR);
/* Get the filter string */ itchMax = LoadString(SC::GetHinst(), ids, pcofn->tszFilter, cA(pcofn->tszFilter));
if (itchMax) { /* Marker character must not be DBCS */ tch = pcofn->tszFilter[itchMax-1]; LPTSTR ptsz = pcofn->tszFilter; while (ptsz < &pcofn->tszFilter[itchMax]) { if (*ptsz == tch) *ptsz++ = '\0'; else ptsz = CharNext(ptsz); } }
/* Set the initial value */ lstrcpyn(pcofn->tsz, pszInit, cA(pcofn->tsz)); }
/*
* Instance info for the dialog. */ typedef struct PIDI { /* PickIcon dialog instance */ LPTSTR ptszIconPath; /* Which file? */ UINT ctchIconPath; int iIconIndex; /* Which icon number? */ int *piIconIndex; TCH tszCurFile[MAX_PATH]; /* The path in the list box */ } PIDI, *PPIDI;
#define cxIcon GetSystemMetrics(SM_CXICON)
#define cyIcon GetSystemMetrics(SM_CYICON)
/*****************************************************************************
* * PickIcon_ppidiHdlg * * Extract the PPIDI from an hdlg. * *****************************************************************************/
#define PickIcon_ppidiHdlg(hdlg) ((PPIDI)GetWindowLongPtr(hdlg, DWLP_USER))
/*****************************************************************************
* * PickIcon_OnMeasureItem * * Tell USER the size of each item. * *****************************************************************************/
void PASCAL PickIcon_OnMeasureItem(HWND hdlg, LPMEASUREITEMSTRUCT lpmi, PPIDI ppidi) { lpmi->itemWidth = cxIcon + 12; lpmi->itemHeight = cyIcon + 4; }
/*****************************************************************************
* * PickIcon_OnDrawItem * * Draw an icon. * *****************************************************************************/
void PASCAL PickIcon_OnDrawItem(HWND hdlg, LPDRAWITEMSTRUCT lpdi, PPIDI ppidi) { SetBkColor(lpdi->hDC, GetSysColor((lpdi->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_WINDOW));
/* repaint the selection state */ ExtTextOut(lpdi->hDC, 0, 0, ETO_OPAQUE, &lpdi->rcItem, NULL, 0, NULL);
/*
* Preserve icon shape when BitBlitting it to a * mirrored DC. */ DWORD dwLayout=0L; if ((dwLayout=GetLayout(lpdi->hDC)) & LAYOUT_RTL) { SetLayout(lpdi->hDC, dwLayout|LAYOUT_BITMAPORIENTATIONPRESERVED); }
/* draw the icon centered in the rectangle */ if ((int)lpdi->itemID >= 0) { DrawIcon(lpdi->hDC, (lpdi->rcItem.left + lpdi->rcItem.right - cxIcon) / 2, (lpdi->rcItem.bottom + lpdi->rcItem.top - cyIcon) / 2, (HICON)lpdi->itemData); }
/*
* Restore the DC to its previous layout state. */ if (dwLayout & LAYOUT_RTL) { SetLayout(lpdi->hDC, dwLayout); }
/* if it has the focus, draw the focus */ if (lpdi->itemState & ODS_FOCUS) { DrawFocusRect(lpdi->hDC, &lpdi->rcItem); } }
/*****************************************************************************
* * PickIcon_OnDeleteItem * * USER is nuking an item. Clean it up. * *****************************************************************************/
#define PickIcon_OnDeleteItem(hdlg, lpdi, ppidi) \
DestroyIcon((HICON)(lpdi)->itemData)
/*****************************************************************************
* * PickIcon_FillIconList * * Fill in all the icons. If the user picks a bad place, we leave * garbage in the path (so he can edit the name) and leave the list * box blank. * *****************************************************************************/
void PickIcon_FillIconList(HWND hdlg, PPIDI ppidi) { HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); HWND hwnd = GetDlgItem(hdlg, IDC_PICKICON); if (!IsWindow (hwnd)) return;
ListBox_SetColumnWidth(hwnd, cxIcon + 12); ListBox_ResetContent(hwnd);
TCHAR szFile[cA(ppidi->tszCurFile)]; GetDlgItemText(hdlg, IDC_PICKPATH, szFile, cA(szFile));
// support indirect paths (e.g. %SystemRoot%\...")
TCHAR szExpandedFile[cA(ppidi->tszCurFile)]; ExpandEnvironmentStrings (szFile, szExpandedFile, cA(szExpandedFile));
if (SearchPath(0, szExpandedFile, 0, cA(ppidi->tszCurFile), ppidi->tszCurFile, 0)) { ExtractIcons: int cIcons; cIcons = ExtractIconEx(ppidi->tszCurFile, 0, 0, 0, 0); if (cIcons) { HICON *rgIcons = (HICON *)LocalAlloc(LPTR, cIcons * sizeof(HICON)); if (rgIcons) { cIcons = (int)ExtractIconEx(ppidi->tszCurFile, 0, rgIcons, NULL, cIcons); if (cIcons) { int iicon; SendMessage(hwnd, WM_SETREDRAW, 0, 0); for (iicon = 0; iicon < cIcons; iicon++) { ListBox_AddString(hwnd, rgIcons[iicon]); } if (ListBox_SetCurSel(hwnd, ppidi->iIconIndex) == LB_ERR) { ListBox_SetCurSel(hwnd, 0); } SendMessage(hwnd, WM_SETREDRAW, 1, 0); } else { /* Mysteriously unable to extract */ } LocalFree((HLOCAL)rgIcons); } else { /* Not enough memory to load icons */ } } else { /* No icons in the file */ } // if indirect path was specified (e.g. "%SystemRoot%\..."), preserve indirection
if ((lstrcmp (szExpandedFile, szFile) != 0) && (lstrcmp (szExpandedFile, ppidi->tszCurFile) == 0)) lstrcpy (ppidi->tszCurFile, szFile); SetDlgItemText(hdlg, IDC_PICKPATH, ppidi->tszCurFile); } else { /* File not found */ SC sc; MMCErrorBox (sc.FromWin32(ERROR_FILE_NOT_FOUND)); goto ExtractIcons; }
InvalidateRect(hwnd, 0, 1); SetCursor(hcurOld); }
/*****************************************************************************
* * PickIcon_OnInitDialog * * Dialog init. Populate the list box with what we came in with. * *****************************************************************************/
void PASCAL PickIcon_OnInitDialog(HWND hdlg, PPIDI ppidi) { SetWindowLongPtr(hdlg, DWLP_USER, (LPARAM)ppidi); SetDlgItemText(hdlg, IDC_PICKPATH, lstrcpyn(ppidi->tszCurFile, ppidi->ptszIconPath, cA(ppidi->tszCurFile))); SendDlgItemMessage(hdlg, IDC_PICKPATH, EM_LIMITTEXT, ppidi->ctchIconPath, 0); PickIcon_FillIconList(hdlg, ppidi); }
/*****************************************************************************
* * PickIcon_OnBrowse * *****************************************************************************/
void PASCAL PickIcon_OnBrowse(HWND hdlg, PPIDI ppidi) { DWORD dw; COFN cofn; InitOpenFileName(hdlg, &cofn, IDS_ICONFILES, ppidi->tszCurFile); dw = GetFileAttributes(ppidi->tszCurFile); if (dw == 0xFFFFFFFF || (dw & FILE_ATTRIBUTE_DIRECTORY)) { cofn.tsz[0] = '\0'; }
if (GetOpenFileName(&cofn.ofn)) { SetDlgItemText(hdlg, IDC_PICKPATH, cofn.tsz); SendMessage(hdlg, DM_SETDEFID, IDOK, 0); PickIcon_FillIconList(hdlg, ppidi); } }
/*****************************************************************************
* * PickIcon_NameChange * * Determine whether the thing in the edit control doesn't match the * thing whose icons we are showing. * *****************************************************************************/
BOOL PASCAL PickIcon_NameChange(HWND hdlg, PPIDI ppidi) { TCH tszBuffer[MAX_PATH]; GetDlgItemText(hdlg, IDC_PICKPATH, tszBuffer, cA(tszBuffer)); return lstrcmpi(tszBuffer, ppidi->tszCurFile); }
/*****************************************************************************
* * PickIcon_OnOk * * If the name has changed, treat this as a "Okay, now reload * the icons" rather than "Okay, I'm finished". * *****************************************************************************/
void PASCAL PickIcon_OnOk(HWND hdlg, PPIDI ppidi) { if (PickIcon_NameChange(hdlg, ppidi)) { PickIcon_FillIconList(hdlg, ppidi); } else { int iIconIndex = (int)SendDlgItemMessage(hdlg, IDC_PICKICON, LB_GETCURSEL, 0, 0L); if (iIconIndex >= 0) { /* We have an icon */ *ppidi->piIconIndex = iIconIndex; lstrcpyn(ppidi->ptszIconPath, ppidi->tszCurFile, ppidi->ctchIconPath); EndDialog(hdlg, 1); } else { /* No icon, act like cancel */ EndDialog(hdlg, 0); } } }
/*****************************************************************************
* * PickIcon_OnCommand * *****************************************************************************/
void PASCAL PickIcon_OnCommand(HWND hdlg, int id, UINT codeNotify, PPIDI ppidi) { switch (id) { case IDOK: PickIcon_OnOk(hdlg, ppidi); break; case IDCANCEL: EndDialog(hdlg, 0); break;
case IDC_PICKBROWSE: PickIcon_OnBrowse(hdlg, ppidi); break;
/*
* When the name changes, remove the selection highlight. */ case IDC_PICKPATH: if (PickIcon_NameChange(hdlg, ppidi)) { SendDlgItemMessage(hdlg, IDC_PICKICON, LB_SETCURSEL, (WPARAM)-1, 0); } break;
case IDC_PICKICON: if (codeNotify == LBN_DBLCLK) { PickIcon_OnOk(hdlg, ppidi); } break; } }
/*****************************************************************************
* * PickIcon_DlgProc * * Dialog procedure. * *****************************************************************************/
/*
* The HANDLE_WM_* macros weren't designed to be used from a dialog * proc, so we need to handle the messages manually. (But carefully.) */
INT_PTR EXPORT PickIcon_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam) { PPIDI ppidi = PickIcon_ppidiHdlg(hdlg);
switch (wm) { case WM_INITDIALOG: PickIcon_OnInitDialog(hdlg, (PPIDI)lParam); break;
case WM_COMMAND: PickIcon_OnCommand(hdlg, (int)GET_WM_COMMAND_ID(wParam, lParam), (UINT)GET_WM_COMMAND_CMD(wParam, lParam), ppidi); break;
case WM_DRAWITEM: PickIcon_OnDrawItem(hdlg, (LPDRAWITEMSTRUCT)lParam, ppidi); break;
case WM_MEASUREITEM: PickIcon_OnMeasureItem(hdlg, (LPMEASUREITEMSTRUCT)lParam, ppidi); break;
case WM_DELETEITEM: PickIcon_OnDeleteItem(hdlg, (LPDELETEITEMSTRUCT)lParam, ppidi); break;
default: return 0; /* Unhandled */ } return 1; /* Handled */ }
/*****************************************************************************
* * PickIconDlg * * Ask the user to pick an icon. * * hwnd - owner window * ptszIconPath - (in) default icon file * (out) chosen icon file * ctchIconPath - size of ptszIconPath buffer * piIconIndex - (in) default icon index * (out) index of chosen icon * * If the dialog box is cancelled, then no values are changed. * *****************************************************************************/
MMCBASE_API INT_PTR PASCAL PickIconDlg(HWND hwnd, LPTSTR ptszIconPath, UINT ctchIconPath, int *piIconIndex) { PIDI pidi;
pidi.ptszIconPath = ptszIconPath; pidi.ctchIconPath = ctchIconPath; pidi.piIconIndex = piIconIndex; pidi.iIconIndex = *piIconIndex;
return DialogBoxParam(SC::GetHinst(), MAKEINTRESOURCE(IDD_PICKICON), hwnd, PickIcon_DlgProc, (LPARAM)&pidi); }
|