2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afs/param.h>
19 #include <WINNT/subclass.h>
20 #include <WINNT/talocale.h>
21 #include <WINNT/dialog.h>
22 #include <WINNT/fastlist.h>
24 #ifdef FORWARD_WM_COMMAND
25 #undef FORWARD_WM_COMMAND
27 #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
28 (fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))
32 * MISCELLANEOUS ______________________________________________________________
37 #define REALLOC(_a,_c,_r,_i) DialogReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
38 BOOL DialogReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
43 if (cReq <= *pcTarget)
46 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
49 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
51 memset (pNew, 0x00, cbElement * cNew);
55 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
66 void DialogGetRectInParent (HWND hWnd, RECT *pr)
70 GetWindowRect (hWnd, pr);
72 pr->right -= pr->left;
73 pr->bottom -= pr->top; // right/bottom == width/height for now
78 ScreenToClient (GetParent (hWnd), &pt);
82 pr->right += pr->left;
83 pr->bottom += pr->top;
88 * PROPERTY SHEETS ____________________________________________________________
92 BOOL PropSheet_HandleNotify (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
97 switch (((NMHDR FAR *)lp)->code)
100 FORWARD_WM_COMMAND (hDlg, IDOK, 0, 0, SendMessage);
103 FORWARD_WM_COMMAND (hDlg, IDAPPLY, 0, 0, SendMessage);
106 FORWARD_WM_COMMAND (hDlg, IDHELP, 0, 0, SendMessage);
109 FORWARD_WM_COMMAND (hDlg, IDINIT, wp, lp, SendMessage);
112 FORWARD_WM_COMMAND (hDlg, IDCANCEL, 0, 0, SendMessage);
128 } *aPropSheets = NULL;
130 static size_t cPropSheets = 0;
133 BOOL CALLBACK PropTab_HookProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
135 if (PropSheet_HandleNotify (hDlg, msg, wp, lp))
138 HWND hSheet = GetParent (hDlg);
139 HWND hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL);
143 for (size_t ii = 0; ii < cPropSheets; ++ii)
145 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
148 if (ii >= cPropSheets)
150 for (size_t ii = 0; ii < cPropSheets; ++ii)
152 if (aPropSheets[ii].fInUse && !aPropSheets[ii].hSheet)
154 aPropSheets[ii].hSheet = hSheet;
159 if (ii < cPropSheets)
161 for (size_t iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
163 if (aPropSheets[ii].psh->aTabs[iTab].hDlg == hDlg)
166 if (iTab == aPropSheets[ii].psh->cTabs)
168 iTab = (size_t)TabCtrl_GetCurSel (hTab);
170 if (iTab < aPropSheets[ii].psh->cTabs)
172 aPropSheets[ii].psh->aTabs[iTab].hDlg = hDlg;
173 BOOL rc = CallWindowProc ((WNDPROC)(aPropSheets[ ii ].psh->aTabs[ iTab ].dlgproc), hDlg, msg, wp, lp);
178 ++ aPropSheets[ ii ].cRef;
182 if (!(-- aPropSheets[ ii ].cRef))
184 PropSheet_Free (aPropSheets[ ii ].psh);
185 aPropSheets[ ii ].fInUse = FALSE;
195 return DefWindowProc (hDlg, msg, wp, lp);
200 LPPROPSHEET PropSheet_Create (LONG idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
202 LPPROPSHEET psh = New (PROPSHEET);
203 memset (psh, 0x00, sizeof(PROPSHEET));
204 psh->sh.dwSize = sizeof(PROPSHEETHEADER);
205 psh->sh.dwFlags = PSH_MODELESS | ((fContextHelp) ? PSH_HASHELP : 0);
206 psh->sh.hwndParent = hParent;
207 psh->sh.hInstance = THIS_HINST;
208 psh->sh.pszCaption = (HIWORD(idsTitle)) ? (LPTSTR)idsTitle : FormatString(TEXT("%1"),TEXT("%m"),idsTitle);
209 psh->fMadeCaption = (HIWORD(idsTitle)) ? FALSE : TRUE;
214 LPPROPSHEET PropSheet_Create (int idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
216 return PropSheet_Create ((LONG)idsTitle, fContextHelp, hParent, lp);
219 LPPROPSHEET PropSheet_Create (LPTSTR pszTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
221 return PropSheet_Create ((LONG)pszTitle, fContextHelp, hParent, lp);
225 BOOL PropSheet_AddTab (LPPROPSHEET psh, LONG idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
227 TCHAR szTitle[ cchRESOURCE ];
230 memset (&psp, 0x00, sizeof(psp));
231 psp.dwSize = sizeof(PROPSHEETPAGE);
232 psp.dwFlags = PSP_DEFAULT | PSP_DLGINDIRECT | (fHelpButton ? PSP_HASHELP : 0);
233 psp.pResource = TaLocale_GetDialogResource (idd, &psp.hInstance);
234 psp.pfnDlgProc = (DLGPROC)PropTab_HookProc;
237 // When first creating the PROPSHEET structure, we had to guess about
238 // which module the tabs would be coming from. Now that we have at least
239 // one tab, we can correct that guess.
241 psh->sh.hInstance = psp.hInstance;
243 if (HIWORD(idsTitle))
245 psp.pszTitle = (LPTSTR)idsTitle;
246 psp.dwFlags |= PSP_USETITLE;
248 else if (idsTitle != 0)
250 GetString (szTitle, idsTitle);
251 psp.pszTitle = szTitle;
252 psp.dwFlags |= PSP_USETITLE;
256 if ((hp = CreatePropertySheetPage (&psp)) == 0)
259 if (!REALLOC( psh->sh.phpage, psh->sh.nPages, 1+psh->sh.nPages, 1))
262 if (!REALLOC( psh->aTabs, psh->cTabs, psh->sh.nPages, 1))
265 psh->aTabs[ psh->sh.nPages-1 ].dlgproc = dlgproc;
266 psh->aTabs[ psh->sh.nPages-1 ].lpUser = lpUser;
267 psh->aTabs[ psh->sh.nPages-1 ].hDlg = 0;
269 psh->sh.phpage[ psh->sh.nPages-1 ] = hp;
271 psh->sh.nStartPage = psh->sh.nPages-1;
276 BOOL PropSheet_AddTab (LPPROPSHEET psh, int idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
278 return PropSheet_AddTab (psh, (LONG)idsTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
281 BOOL PropSheet_AddTab (LPPROPSHEET psh, LPTSTR pszTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
283 return PropSheet_AddTab (psh, (LONG)pszTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
287 void PropSheet_NotifyAllTabs (LPPROPSHEET psh, HWND hDlg, UINT msg)
289 for (size_t ii = 0; ii < psh->cTabs; ++ii)
291 if (psh->aTabs[ ii ].dlgproc)
293 CallWindowProc ((WNDPROC)(psh->aTabs[ ii ].dlgproc), hDlg, msg, (WPARAM)psh, psh->aTabs[ ii ].lpUser);
299 BOOL CALLBACK PropSheet_HookProc (HWND hSheet, UINT msg, WPARAM wp, LPARAM lp)
301 PVOID oldproc = Subclass_FindNextHook (hSheet, PropSheet_HookProc);
305 rc = CallWindowProc ((WNDPROC)oldproc, hSheet, msg, wp, lp);
307 rc = DefWindowProc (hSheet, msg, wp, lp);
313 for (ii = 0; ii < cPropSheets; ++ii)
315 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
318 if (ii < cPropSheets)
320 for (size_t iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
322 if ( (aPropSheets[ii].psh->aTabs[iTab].hDlg) &&
323 (IsWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg)) &&
324 (aPropSheets[ii].psh->aTabs[iTab].dlgproc != NULL) )
326 DestroyWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg);
330 PropSheet_NotifyAllTabs (aPropSheets[ ii ].psh, hSheet, WM_DESTROY_SHEET);
332 if (!(-- aPropSheets[ ii ].cRef))
334 PropSheet_Free (aPropSheets[ ii ].psh);
335 aPropSheets[ ii ].fInUse = FALSE;
339 Subclass_RemoveHook (hSheet, PropSheet_HookProc);
347 LPARAM PropSheet_FindTabParam (HWND hTab)
349 for (size_t ii = 0; ii < cPropSheets; ++ii)
351 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hTab))
352 return aPropSheets[ii].psh->lpUser;
355 HWND hSheet = GetParent (hTab);
356 for (ii = 0; ii < cPropSheets; ++ii)
358 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
361 if (ii < cPropSheets)
363 for (size_t iTab = 0; iTab < aPropSheets[ ii ].psh->cTabs; ++iTab)
365 if (hTab == aPropSheets[ ii ].psh->aTabs[ iTab ].hDlg)
366 return aPropSheets[ ii ].psh->aTabs[ iTab ].lpUser;
374 BOOL PropSheet_ShowModal (LPPROPSHEET psh, void (*fnPump)(MSG *lpm))
377 if ((hSheet = PropSheet_ShowModeless (psh, SW_SHOW)) == NULL)
380 BOOL fWasEnabled = TRUE;
381 HWND hParent = psh->sh.hwndParent;
382 if (hParent && IsWindow (hParent))
384 fWasEnabled = IsWindowEnabled (hParent);
385 EnableWindow (hParent, FALSE);
389 while (GetMessage (&msg, NULL, 0, 0))
391 if (IsMemoryManagerMessage (&msg))
394 if (!PropSheet_GetCurrentPageHwnd (hSheet))
396 if (hParent && IsWindow (hParent))
397 EnableWindow (hParent, fWasEnabled);
398 DestroyWindow (hSheet);
401 if (!IsWindow (hSheet))
407 TranslateMessage (&msg);
408 DispatchMessage (&msg);
413 if (PropSheet_IsDialogMessage (hSheet, &msg))
420 TranslateMessage (&msg);
421 DispatchMessage (&msg);
425 if (hParent && IsWindow (hParent))
426 EnableWindow (hParent, fWasEnabled);
432 HWND PropSheet_ShowModeless (LPPROPSHEET psh, int nCmdShow)
434 // Write down that we're opening a property sheet. Since we
435 // don't know the window handle yet, we'll set it to zero--
436 // when PropSheetTab_HookProc gets called for a property sheet
437 // that doesn't seem to be listed, it will write down hSheet for us.
438 // This way, we get the aPropSheets[] array filled in--complete with
439 // window handle--*before* the tabs themselves get any messages.
440 // Otherwise, we'd have to wait until the WM_INITDIALOG/IDINIT
441 // messages were finished.
443 for (size_t ii = 0; ii < cPropSheets; ++ii)
445 if (!aPropSheets[ ii ].fInUse)
448 if (!REALLOC (aPropSheets, cPropSheets, 1+ii, 4))
450 aPropSheets[ ii ].fInUse = TRUE;
451 aPropSheets[ ii ].hSheet = 0;
452 aPropSheets[ ii ].psh = psh;
453 aPropSheets[ ii ].cRef = 1;
455 // Open the property sheet dialog.
457 psh->sh.dwFlags |= PSH_MODELESS;
460 if ((hSheet = (HWND)PropertySheet (&psh->sh)) == NULL)
463 // Tell all tabs (not just the first one) that the sheet has been
464 // created. We'll also want to hook the sheet itself here, so we can
465 // clean up when it's destroyed.
467 Subclass_AddHook (hSheet, PropSheet_HookProc);
468 PropSheet_NotifyAllTabs (psh, hSheet, WM_INITDIALOG_SHEET);
469 ShowWindow (hSheet, nCmdShow);
475 void PropSheet_Free (LPPROPSHEET psh)
481 Free (psh->sh.phpage);
483 if (psh->fMadeCaption && psh->sh.pszCaption)
485 FreeString (psh->sh.pszCaption);
497 HWND PropSheet_FindTabWindow (LPPROPSHEET psh, DLGPROC dlgproc)
501 for (size_t iTab = 0; iTab < psh->cTabs; ++iTab)
503 if (dlgproc == psh->aTabs[ iTab ].dlgproc)
504 return psh->aTabs[ iTab ].hDlg;
511 void PropSheetChanged (HWND hDlg)
513 PropSheet_Changed (GetParent(hDlg), hDlg);
517 void TabCtrl_SwitchToTab (HWND hTab, int iTab)
519 TabCtrl_SetCurSel (hTab, iTab);
523 nm.idFrom = IDC_PROPSHEET_TABCTRL;
524 nm.code = TCN_SELCHANGE;
525 SendMessage (GetParent (hTab), WM_NOTIFY, 0, (LPARAM)&nm);
530 * LISTVIEW ___________________________________________________________________
534 LPARAM FL_StartChange (HWND hList, BOOL fReset)
536 LPARAM dwSelected = FL_GetSelectedData (hList);
537 FastList_Begin (hList);
539 FastList_RemoveAll (hList);
544 void FL_EndChange (HWND hList, LPARAM lpToSelect)
547 FL_SetSelectedByData (hList, lpToSelect);
548 FastList_EndAll (hList);
552 void FL_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
554 for (WORD ii = 0; ii < nCols; ++ii)
557 FastList_GetColumn (hList, ii, &flc);
559 flc.cxWidth = acx[ ii ];
560 FastList_SetColumn (hList, ii, &flc);
565 void cdecl FL_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
570 for (WORD ii = 0; ii < nCols; ii++)
573 GetString (flc.szText, va_arg (arg, WORD));
574 flc.dwFlags = FLCF_JUSTIFY_LEFT;
575 flc.cxWidth = acx[ ii ]; // width of the column, in pixels
576 FastList_SetColumn (hList, ii, &flc);
581 void FL_GetColumns (HWND hList, WORD nCols, WORD *acx)
583 for (WORD ii = 0; ii < nCols; ii++)
586 FastList_GetColumn (hList, ii, &flc);
587 acx[ ii ] = (WORD)flc.cxWidth;
592 HLISTITEM cdecl FL_AddItem (HWND hList, WORD nCols, LPARAM lp, int iImage1, ...)
595 va_start (arg, iImage1);
597 FASTLISTADDITEM flai;
598 memset (&flai, 0x00, sizeof(flai));
600 flai.iFirstImage = iImage1;
601 flai.iSecondImage = IMAGE_NOIMAGE;
602 flai.pszText = va_arg (arg, LPTSTR);
606 FastList_Begin (hList);
609 if ((hItem = FastList_AddItem (hList, &flai)) != NULL)
611 for (WORD ii = 1; ii < nCols; ii++)
613 FastList_SetItemText (hList, hItem, ii, va_arg (arg, LPTSTR));
617 FastList_End (hList);
622 void FL_GetItemText (HWND hList, HLISTITEM hItem, int iCol, LPTSTR psz)
624 LPCTSTR pszText = FastList_GetItemText (hList, hItem, iCol);
628 lstrcpy (psz, pszText);
632 void FL_SetItemText (HWND hList, HLISTITEM hItem, int iCol, LPCTSTR psz)
634 FastList_SetItemText (hList, hItem, iCol, psz);
638 void FL_SetSelectedByData (HWND hList, LPARAM lp)
641 if ((hItem = FastList_FindItem (hList, lp)) != NULL)
643 FL_SetSelected (hList, hItem);
648 void FL_SetSelected (HWND hList, HLISTITEM hItem)
650 FastList_Begin (hList);
651 FastList_SelectNone (hList);
654 FastList_SelectItem (hList, hItem, TRUE);
655 FastList_EnsureVisible (hList, hItem);
657 FastList_SetFocus (hList, hItem);
658 FastList_End (hList);
662 HLISTITEM FL_GetSelected (HWND hList, HLISTITEM hItem)
664 return FastList_FindNextSelected (hList, hItem);
668 HLISTITEM FL_GetFocused (HWND hList)
670 return FastList_GetFocus (hList);
674 LPARAM FL_GetFocusedData (HWND hList)
677 if ((hItem = FastList_GetFocus (hList)) == NULL)
680 return FastList_GetItemParam (hList, hItem);
684 LPARAM FL_GetData (HWND hList, HLISTITEM hItem)
686 return FastList_GetItemParam (hList, hItem);
690 HLISTITEM FL_GetIndex (HWND hList, LPARAM lp)
692 return FastList_FindItem (hList, lp);
696 LPARAM FL_GetSelectedData (HWND hList)
699 if ((hItem = FastList_FindFirstSelected (hList)) == NULL)
702 return FastList_GetItemParam (hList, hItem);
706 void FL_RestoreView (HWND hList, LPVIEWINFO lpvi)
708 FastList_Begin (hList);
710 for (size_t cColumns = FastList_GetColumnCount(hList); cColumns; --cColumns)
712 FastList_RemoveColumn (hList, cColumns-1);
715 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
717 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
720 size_t iColumn = lpvi->aColumns[ ii ];
723 GetString (flc.szText, lpvi->idsColumns[ iColumn ]);
725 flc.dwFlags = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? FLCF_JUSTIFY_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? FLCF_JUSTIFY_CENTER : FLCF_JUSTIFY_LEFT;
726 flc.cxWidth = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
727 FastList_SetColumn (hList, ii, &flc);
730 // Restore the fastlist's sort style
732 FastList_SetSortStyle (hList, (lpvi->iSort & (~COLUMN_SORTREV)), !!(lpvi->iSort & COLUMN_SORTREV));
734 // Switch the FastList into the proper mode--Large Icons,
735 // Small Icons, List or Details.
737 LONG dw = GetWindowLong (hList, GWL_STYLE);
738 dw &= ~FLS_VIEW_MASK;
740 SetWindowLong (hList, GWL_STYLE, dw);
742 FastList_End (hList);
746 void FL_StoreView (HWND hList, LPVIEWINFO lpvi)
748 // First, remember what mode the the FastList is in--Large,
749 // Small, List, Tree, or TreeList.
751 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
752 lpvi->lvsView &= FLS_VIEW_MASK;
754 // Record the fastlist's sort style
758 FastList_GetSortStyle (hList, &iCol, &fRev);
759 lpvi->iSort = (size_t)iCol;
761 lpvi->iSort |= COLUMN_SORTREV;
763 // Then remember the columns' widths; we expect that the columns
764 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
767 if (lpvi->lvsView & FLS_VIEW_LIST)
769 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
771 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
774 size_t iColumn = lpvi->aColumns[ii];
776 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
779 FastList_GetColumn (hList, ii, &flc);
780 lpvi->cxColumns[ iColumn ] = flc.cxWidth | dwJust;
786 HLISTITEM cdecl FL_AddItem (HWND hList, LPVIEWINFO lpvi, LPARAM lp, int iImage1, ...)
789 va_start (arg, iImage1);
791 LPTSTR apszColumns[ nCOLUMNS_MAX ];
792 for (size_t iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
794 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
797 FastList_Begin (hList);
799 HLISTITEM hItem = NULL;
800 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
802 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
807 FASTLISTADDITEM flai;
808 memset (&flai, 0x00, sizeof(flai));
810 flai.iFirstImage = iImage1;
811 flai.iSecondImage = IMAGE_NOIMAGE;
812 flai.pszText = apszColumns[ iColumn ];
816 hItem = FastList_AddItem (hList, &flai);
820 FastList_SetItemText (hList, hItem, ii, apszColumns[ iColumn ]);
824 FastList_End (hList);
829 BOOL FL_HitTestForHeaderBar (HWND hList, POINT ptClient)
831 for (HWND hHeader = GetWindow (hList, GW_CHILD);
833 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
835 TCHAR szClassName[ cchRESOURCE ];
837 if (GetClassName (hHeader, szClassName, cchRESOURCE))
839 if (!lstrcmp (szClassName, WC_HEADER))
844 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
847 DialogGetRectInParent (hHeader, &rHeader);
848 if (PtInRect (&rHeader, ptClient))
858 * LISTVIEW ___________________________________________________________________
862 LPARAM LV_StartChange (HWND hList, BOOL fReset)
864 LPARAM dwSelected = LV_GetSelectedData (hList);
865 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
867 ListView_DeleteAllItems (hList);
872 void LV_EndChange (HWND hList, LPARAM lpToSelect)
874 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
876 if (lpToSelect != (LPARAM)NULL)
877 LV_SetSelectedByData (hList, lpToSelect);
881 void LV_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
883 for (WORD ii = 0; ii < nCols; ++ii)
885 ListView_SetColumnWidth (hList, ii, acx[ ii ]);
889 void cdecl LV_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
894 for (WORD ii = 0; ii < nCols; ii++)
897 TCHAR text[ cchRESOURCE ];
899 GetString (text, va_arg (arg, WORD));
901 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
902 lvC.fmt = LVCFMT_LEFT;
904 lvC.cx = acx[ ii ]; // width of the column, in pixels
906 ListView_InsertColumn (hList, ii, &lvC);
911 void LV_GetColumns (HWND hList, WORD nCols, WORD *acx)
913 for (WORD ii = 0; ii < nCols; ii++)
915 acx[ ii ] = ListView_GetColumnWidth (hList, ii);
920 void cdecl LV_AddItem (HWND hList, WORD nCols, int index, LPARAM lp, int iImage, ...)
924 va_start (arg, iImage);
926 lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
931 lvI.pszText = va_arg (arg, LPTSTR);
932 lvI.cchTextMax = cchRESOURCE;
936 if ((index == INDEX_SORT) && (lvI.pszText != LPSTR_TEXTCALLBACK))
938 lvI.iItem = LV_PickInsertionPoint (hList, lvI.pszText);
941 DWORD dw = ListView_InsertItem (hList, &lvI);
943 for (WORD ii = 1; ii < nCols; ii++)
945 ListView_SetItemText (hList, dw, ii, va_arg (arg, LPTSTR));
950 void cdecl LV_GetItemText (HWND hList, int index, short col, LPTSTR psz)
953 ListView_GetItemText (hList, index, col, (LPTSTR)psz, cchRESOURCE);
957 void cdecl LV_SetItemText (HWND hList, int index, short col, LPCTSTR psz)
959 ListView_SetItemText (hList, index, col, (LPTSTR)psz);
963 void LV_SetSelectedByData (HWND hList, LPARAM lp)
967 if ((index = LV_GetIndex (hList, lp)) != -1)
969 LV_SetSelected (hList, index);
974 void LV_SetSelected (HWND hList, int index)
976 ListView_EnsureVisible (hList, index, FALSE);
978 ListView_SetItemState (hList, index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
982 int LV_GetSelected (HWND hList, int index)
984 return ListView_GetNextItem (hList, index, LVNI_SELECTED);
988 int LV_GetFocused (HWND hList)
990 return ListView_GetNextItem (hList, -1, LVNI_FOCUSED);
994 LPARAM LV_GetFocusedData (HWND hList)
998 if ((idxFocus = LV_GetFocused (hList)) == -1)
1001 return LV_GetData (hList, idxFocus);
1005 LPARAM LV_GetData (HWND hList, int index)
1009 memset (&lvI, 0x00, sizeof(LV_ITEM));
1010 lvI.mask = LVIF_PARAM;
1013 if (! ListView_GetItem (hList, &lvI))
1020 int LV_GetIndex (HWND hList, LPARAM lp)
1024 memset (&lvfi, 0x00, sizeof(lvfi));
1026 lvfi.flags = LVFI_PARAM;
1029 return ListView_FindItem (hList, -1, &lvfi);
1033 LPARAM LV_GetSelectedData (HWND hList)
1037 if ((index = LV_GetSelected (hList)) == -1)
1040 return LV_GetData (hList, index);
1044 void LV_RestoreView (HWND hList, LPVIEWINFO lpvi)
1046 // Add columns to the listview; remember that we'll have to remove any
1047 // existing columns first.
1049 while (ListView_DeleteColumn (hList, 0))
1052 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1054 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1057 size_t iColumn = lpvi->aColumns[ii];
1061 TCHAR szText[ cchRESOURCE ];
1062 GetString (szText, lpvi->idsColumns[ iColumn ]);
1064 lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
1065 lvc.fmt = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? LVCFMT_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? LVCFMT_CENTER : LVCFMT_LEFT;
1066 lvc.pszText = szText;
1067 lvc.cx = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
1069 ListView_InsertColumn (hList, ii, &lvc);
1072 // Switch the ListView into the proper mode--Large Icons,
1073 // Small Icons, List or Details.
1075 LONG dw = GetWindowLong (hList, GWL_STYLE);
1076 dw &= ~LVS_TYPEMASK;
1077 dw |= lpvi->lvsView;
1078 dw |= LVS_AUTOARRANGE;
1079 SetWindowLong (hList, GWL_STYLE, dw);
1080 ListView_Arrange (hList, LVA_DEFAULT);
1084 void LV_StoreView (HWND hList, LPVIEWINFO lpvi)
1086 // First, remember what mod the the ListView is in--Large Icons,
1087 // Small Icons, List or Details.
1089 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
1090 lpvi->lvsView &= LVS_TYPEMASK;
1092 // Then remember the columns' widths; we expect that the columns
1093 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
1096 if (lpvi->lvsView == LVS_REPORT)
1098 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1100 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1103 size_t iColumn = lpvi->aColumns[ii];
1105 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
1107 lpvi->cxColumns[ iColumn ] = ListView_GetColumnWidth (hList, ii);
1108 lpvi->cxColumns[ iColumn ] |= dwJust;
1114 typedef struct // VIEWSORTINFO
1120 } VIEWSORTINFO, *LPVIEWSORTINFO;
1122 BOOL CALLBACK LV_SortView_Numeric (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1124 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1125 TCHAR szText[ cchRESOURCE ];
1129 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1130 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1132 LV_GetItemText (lpvsi->hList, ii1, lpvsi->iColSort, szText);
1135 LV_GetItemText (lpvsi->hList, ii2, lpvsi->iColSort, szText);
1138 if (lpvsi->fAscending)
1139 return (d2 < d1) ? ((BOOL)-1) : (d2 == d1) ? ((BOOL)0) : (BOOL)1;
1141 return (d1 < d2) ? ((BOOL)-1) : (d1 == d2) ? ((BOOL)0) : (BOOL)1;
1145 BOOL CALLBACK LV_SortView_Alphabetic (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1147 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1148 TCHAR szText1[ cchRESOURCE ];
1149 TCHAR szText2[ cchRESOURCE ];
1151 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1152 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1154 LV_GetItemText (lpvsi->hList, ii1, lpvsi->iColSort, szText1);
1155 LV_GetItemText (lpvsi->hList, ii2, lpvsi->iColSort, szText2);
1157 if (lpvsi->fAscending)
1158 return lstrcmp (szText2, szText1);
1160 return lstrcmp (szText1, szText2);
1164 void LV_SortView (HWND hList, LPVIEWINFO lpvi)
1166 for (size_t iColSort = 0; iColSort < lpvi->nColsShown; ++iColSort)
1168 if ((lpvi->iSort & (~COLUMN_SORTREV)) == lpvi->aColumns[ iColSort ])
1172 if (iColSort < lpvi->nColsShown)
1177 vsi.iColSort = iColSort;
1178 vsi.fAscending = (lpvi->iSort & COLUMN_SORTREV) ? TRUE : FALSE;
1180 if (lpvi->cxColumns[ lpvi->iSort ] & COLUMN_RIGHTJUST)
1181 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Numeric, (LPARAM)&vsi);
1183 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Alphabetic, (LPARAM)&vsi);
1188 void cdecl LV_AddItem (HWND hList, LPVIEWINFO lpvi, int index, LPARAM lp, int iImage, ...)
1191 va_start (arg, iImage);
1193 LPTSTR apszColumns[ nCOLUMNS_MAX ];
1194 for (size_t iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
1196 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
1199 if ((index == INDEX_SORT) && (iColumn) && (apszColumns[0] != LPSTR_TEXTCALLBACK))
1201 index = LV_PickInsertionPoint (hList, apszColumns[0]);
1205 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1207 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
1213 lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
1215 lvitem.stateMask = 0;
1216 lvitem.iItem = index;
1217 lvitem.iSubItem = 0;
1218 lvitem.pszText = apszColumns[ iColumn ];
1219 lvitem.cchTextMax = cchRESOURCE;
1220 lvitem.iImage = iImage;
1223 dw = ListView_InsertItem (hList, &lvitem);
1227 ListView_SetItemText (hList, dw, ii, apszColumns[ iColumn ]);
1233 BOOL LV_HitTestForHeaderBar (HWND hList, POINT ptClient)
1235 for (HWND hHeader = GetWindow (hList, GW_CHILD);
1237 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
1239 TCHAR szClassName[ cchRESOURCE ];
1241 if (GetClassName (hHeader, szClassName, cchRESOURCE))
1243 if (!lstrcmp (szClassName, WC_HEADER))
1248 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
1251 DialogGetRectInParent (hHeader, &rHeader);
1252 if (PtInRect (&rHeader, ptClient))
1260 int LV_PickInsertionPoint (HWND hList, LPTSTR pszNewItem, int (__stdcall *fnSort)(LPCTSTR, LPCTSTR))
1263 int iItemHigh = ListView_GetItemCount (hList) -1;
1268 while (iItemLow <= iItemHigh)
1270 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
1272 TCHAR szItemTest[ 256 ];
1273 ListView_GetItemText (hList, iItemTest, 0, szItemTest, 256);
1275 int iCompare = (*fnSort)(pszNewItem, szItemTest);
1278 if ((iItemHigh = iItemTest-1) < iItemLow)
1279 return iItemHigh +1;
1283 if ((iItemLow = iItemTest+1) > iItemHigh)
1294 * COMBO BOXES ________________________________________________________________
1298 LPARAM CB_StartChange (HWND hCombo, BOOL fReset)
1300 LPARAM dwSelected = CB_GetSelectedData (hCombo);
1301 SendMessage (hCombo, WM_SETREDRAW, FALSE, 0);
1303 SendMessage (hCombo, CB_RESETCONTENT, 0, 0);
1308 void CB_EndChange (HWND hCombo, LPARAM lpToSelect)
1310 SendMessage (hCombo, WM_SETREDRAW, TRUE, 0);
1312 if (lpToSelect != (LPARAM)NULL)
1313 CB_SetSelectedByData (hCombo, lpToSelect);
1317 UINT CB_AddItem (HWND hCombo, int nsz, LPARAM lp)
1322 psz = FormatString (nsz);
1323 rc = CB_AddItem (hCombo, psz, lp);
1330 UINT CB_AddItem (HWND hCombo, LPCTSTR psz, LPARAM lp)
1333 if ((index = (UINT)SendMessage (hCombo, CB_ADDSTRING, 0, (LPARAM)psz)) != (UINT)-1)
1335 SendMessage (hCombo, CB_SETITEMDATA, index, lp);
1341 void CB_SetSelected (HWND hCombo, UINT index)
1343 SendMessage (hCombo, CB_SETCURSEL, index, 0);
1347 void CB_SetSelectedByData (HWND hCombo, LPARAM lpMatch)
1349 CB_SetSelected (hCombo, CB_GetIndex (hCombo, lpMatch));
1353 UINT CB_GetSelected (HWND hCombo)
1355 return (UINT)SendMessage (hCombo, CB_GETCURSEL, 0, 0);
1359 LPARAM CB_GetSelectedData (HWND hCombo)
1363 if ((index = CB_GetSelected (hCombo)) == -1)
1366 return CB_GetData (hCombo, index);
1370 LPARAM CB_GetData (HWND hCombo, UINT index)
1372 return (LPARAM)SendMessage (hCombo, CB_GETITEMDATA, index, 0);
1376 UINT CB_GetIndex (HWND hCombo, LPARAM lpMatch)
1378 UINT idxMax = (UINT)SendMessage (hCombo, CB_GETCOUNT, 0, 0);
1380 for (UINT index = 0; index < idxMax; index++)
1382 if (SendMessage (hCombo, CB_GETITEMDATA, index, 0) == lpMatch)
1391 * LIST BOXES _________________________________________________________________
1395 LPARAM LB_StartChange (HWND hList, BOOL fReset)
1397 LPARAM dwSelected = LB_GetSelectedData (hList);
1398 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
1400 SendMessage (hList, LB_RESETCONTENT, 0, 0);
1405 void LB_EndChange (HWND hList, LPARAM lpToSelect)
1407 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
1409 if (lpToSelect != (LPARAM)NULL)
1410 LB_SetSelectedByData (hList, lpToSelect);
1414 UINT LB_AddItem (HWND hList, int nsz, LPARAM lp)
1419 psz = FormatString (nsz);
1420 rc = LB_AddItem (hList, psz, lp);
1427 UINT LB_AddItem (HWND hList, LPCTSTR psz, LPARAM lp)
1430 if ((index = (UINT)SendMessage (hList, LB_ADDSTRING, 0, (LPARAM)psz)) != -1)
1432 SendMessage (hList, LB_SETITEMDATA, index, lp);
1438 void LB_EnsureVisible (HWND hList, UINT index)
1441 if ((cyItem = SendMessage (hList, LB_GETITEMHEIGHT, 0, 0)) != 0)
1444 GetClientRect (hList, &rClient);
1446 if ((cWindow = cyRECT(rClient) / cyItem) == 0)
1449 int idxTop = SendMessage (hList, LB_GETTOPINDEX, 0, 0);
1450 if (index < (UINT)idxTop)
1452 SendMessage (hList, LB_SETTOPINDEX, index, 0);
1454 else if (index >= (UINT)(idxTop +cWindow))
1456 SendMessage (hList, LB_SETTOPINDEX, index -cWindow +1, 0);
1462 void LB_SetSelected (HWND hList, UINT index)
1464 SendMessage (hList, LB_SETCURSEL, index, 0);
1465 LB_EnsureVisible (hList, index);
1469 void LB_SetSelectedByData (HWND hList, LPARAM lpMatch)
1471 LB_SetSelected (hList, LB_GetIndex (hList, lpMatch));
1475 UINT LB_GetSelected (HWND hList)
1477 return (UINT)SendMessage (hList, LB_GETCURSEL, 0, 0);
1481 LPARAM LB_GetSelectedData (HWND hList)
1485 if ((index = LB_GetSelected (hList)) == (UINT)-1)
1488 return LB_GetData (hList, index);
1492 LPARAM LB_GetData (HWND hList, UINT index)
1494 return (LPARAM)SendMessage (hList, LB_GETITEMDATA, index, 0);
1498 UINT LB_GetIndex (HWND hList, LPARAM lpMatch)
1500 UINT idxMax = (UINT)SendMessage (hList, LB_GETCOUNT, 0, 0);
1502 for (UINT index = 0; index < idxMax; index++)
1504 if (SendMessage (hList, LB_GETITEMDATA, index, 0) == lpMatch)
1512 WORD LB_GetStringExtent (HWND hList, LPTSTR pszString)
1514 HDC hdc = GetDC (hList);
1517 GetTextExtentPoint32 (hdc, pszString, lstrlen(pszString), &sz);
1519 ReleaseDC (hList, hdc);
1520 return (WORD)( sz.cx + 2 * GetSystemMetrics (SM_CXBORDER) );
1524 BOOL CALLBACK ListBox_HScrollHook (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
1526 PVOID oldProc = Subclass_FindNextHook (hList, ListBox_HScrollHook);
1531 Subclass_RemoveHook (hList, ListBox_HScrollHook);
1536 LPTSTR pszString = (LPTSTR)lp;
1537 WORD cxString = LB_GetStringExtent (hList, pszString);
1538 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1539 if (cxString > cxExtent)
1540 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxString, 0);
1544 case LB_DELETESTRING:
1546 int iItemSkip = (int)wp;
1547 int iItemMax = SendMessage (hList, LB_GETCOUNT, 0, 0);
1550 for (int iItem = 0; iItem < iItemMax; iItem++)
1552 if (iItem == iItemSkip)
1554 int cch = SendMessage (hList, LB_GETTEXTLEN, (WPARAM)iItem, 0);
1555 cchMax = max (cch, cchMax);
1558 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1559 WORD cxStringMax = 0;
1560 LPTSTR pszString = AllocateString (cchMax +1);
1562 for (iItem = 0; iItem < iItemMax; iItem++)
1564 if (iItem == iItemSkip)
1566 SendMessage (hList, LB_GETTEXT, (WPARAM)iItem, (LPARAM)pszString);
1567 WORD cxString = LB_GetStringExtent (hList, pszString);
1568 cxStringMax = max (cxString, cxStringMax);
1571 FreeString (pszString);
1572 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxStringMax, 0);
1578 return CallWindowProc ((WNDPROC)oldProc, hList, msg, wp, lp);
1580 return DefWindowProc (hList, msg, wp, lp);
1584 void LB_EnableHScroll (HWND hList)
1586 Subclass_AddHook (hList, ListBox_HScrollHook);
1591 * TREEVIEWS __________________________________________________________________
1595 LPARAM TV_GetData (HWND hTree, HTREEITEM hti)
1600 tvi.mask = TVIF_PARAM;
1602 if (!TreeView_GetItem (hTree, &tvi))
1603 return (LPARAM)NULL;
1609 LPARAM TV_GetSelectedData (HWND hTree)
1611 HTREEITEM hti = TreeView_GetSelection (hTree);
1616 return TV_GetData (hTree, hti);
1620 LPARAM TV_StartChange (HWND hTree, BOOL fReset)
1622 LPARAM dwSelected = TV_GetSelectedData (hTree);
1623 SendMessage (hTree, WM_SETREDRAW, FALSE, 0);
1625 TreeView_DeleteAllItems (hTree);
1630 void TV_EndChange (HWND hTree, LPARAM lpToSelect)
1632 SendMessage (hTree, WM_SETREDRAW, TRUE, 0);
1634 if (lpToSelect != NULL)
1636 HTREEITEM hti = TV_RecursiveFind (hTree, TVI_ROOT, lpToSelect);
1638 TreeView_SelectItem (hTree, hti);
1643 HTREEITEM TV_RecursiveFind (HWND hTree, HTREEITEM htiRoot, LPARAM lpToFind)
1645 for (HTREEITEM hti = (htiRoot == TVI_ROOT) ? TreeView_GetRoot (hTree) : TreeView_GetChild (hTree, htiRoot);
1647 hti = TreeView_GetNextSibling (hTree, hti))
1649 if (lpToFind == TV_GetData (hTree, hti))
1653 if ((htiFound = TV_RecursiveFind (hTree, hti, lpToFind)) != NULL)
1662 * COMMON DIALOGS _____________________________________________________________
1666 BOOL Browse_Open (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1668 TCHAR szFilter[ cchRESOURCE ];
1669 GetString (szFilter, idsFilter);
1670 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1671 for (LPTSTR pszFilter = szFilter;
1672 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1675 *pszFilter = TEXT('\0');
1679 memset (&ofn, 0x00, sizeof(ofn));
1680 ofn.lStructSize = sizeof(ofn);
1681 ofn.hwndOwner = hParent;
1682 ofn.hInstance = THIS_HINST;
1683 ofn.lpstrFilter = szFilter;
1684 ofn.nFilterIndex = 1;
1685 ofn.lpstrFile = pszFilename;
1686 ofn.nMaxFile = MAX_PATH;
1687 ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
1688 ofn.lCustData = lCustData;
1690 if (iddTemplate != 0)
1692 ofn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1693 ofn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1695 if (lpfnHook != NULL)
1697 ofn.lpfnHook = lpfnHook;
1698 ofn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1701 TCHAR szPath[ MAX_PATH ];
1702 GetCurrentDirectory (MAX_PATH, szPath);
1703 if (pszLastDirectory && *pszLastDirectory)
1704 SetCurrentDirectory (pszLastDirectory);
1706 BOOL rc = GetOpenFileName (&ofn);
1708 if (pszLastDirectory)
1709 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1710 SetCurrentDirectory (szPath);
1716 BOOL Browse_Save (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1718 TCHAR szFilter[ cchRESOURCE ];
1719 GetString (szFilter, idsFilter);
1720 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1721 for (LPTSTR pszFilter = szFilter;
1722 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1725 *pszFilter = TEXT('\0');
1729 memset (&sfn, 0x00, sizeof(sfn));
1730 sfn.lStructSize = sizeof(sfn);
1731 sfn.hwndOwner = hParent;
1732 sfn.hInstance = THIS_HINST;
1733 sfn.lpstrFilter = szFilter;
1734 sfn.nFilterIndex = 1;
1735 sfn.lpstrFile = pszFilename;
1736 sfn.nMaxFile = MAX_PATH;
1737 sfn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
1738 sfn.lCustData = lCustData;
1740 if (iddTemplate != 0)
1742 sfn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1743 sfn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1745 if (lpfnHook != NULL)
1747 sfn.lpfnHook = lpfnHook;
1748 sfn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1751 TCHAR szPath[ MAX_PATH ];
1752 GetCurrentDirectory (MAX_PATH, szPath);
1753 if (pszLastDirectory && *pszLastDirectory)
1754 SetCurrentDirectory (pszLastDirectory);
1756 BOOL rc = GetSaveFileName (&sfn);
1758 if (pszLastDirectory)
1759 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1760 SetCurrentDirectory (szPath);
1767 * HOURGLASS CURSOR ETC _______________________________________________________
1771 static LONG nHourGlassRequests = 0;
1773 void StartHourGlass (void)
1775 if ((++nHourGlassRequests) == 1)
1777 SetCursor (LoadCursor (NULL, IDC_WAIT));
1781 void StopHourGlass (void)
1783 if ((nHourGlassRequests == 0) || ((--nHourGlassRequests) == 0))
1785 SetCursor (LoadCursor (NULL, IDC_ARROW));
1791 void DisplayContextMenu (HMENU hm, POINT ptScreen, HWND hParent)
1793 HMENU hmDummy = CreateMenu();
1794 InsertMenu (hmDummy, 0, MF_POPUP, (UINT)hm, NULL);
1796 TrackPopupMenu (GetSubMenu (hmDummy, 0),
1797 TPM_LEFTALIGN | TPM_RIGHTBUTTON,
1798 ptScreen.x, ptScreen.y,
1801 DestroyMenu (hmDummy);
1805 size_t CountChildren (HWND hParent, LPTSTR pszClass)
1809 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1811 hChild = GetWindow (hChild, GW_HWNDNEXT))
1813 TCHAR szClassName[ cchRESOURCE ];
1815 if (GetClassName (hChild, szClassName, cchRESOURCE))
1817 if (!lstrcmp (szClassName, pszClass))
1826 WORD NextControlID (HWND hParent)
1830 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1832 hChild = GetWindow (hChild, GW_HWNDNEXT))
1834 LONG wChild = GetWindowLong (hChild, GWL_ID);
1835 if ((wChild < 0) || (wChild >= 0xF000))
1838 wNext = max( wNext, (WORD) wChild+1 );
1845 BOOL IsAncestor (HWND hParent, HWND hChild)
1847 for ( ; hChild; hChild = GetParent(hChild))
1849 if (hParent == hChild)
1856 HWND GetTabChild (HWND hTab)
1858 for (HWND hChild = GetWindow (hTab, GW_CHILD);
1860 hChild = GetWindow (hChild, GW_HWNDNEXT))
1862 TCHAR szClassName[ cchRESOURCE ];
1864 if (GetClassName (hChild, szClassName, cchRESOURCE))
1866 if (!lstrcmp (szClassName, TEXT("#32770"))) // WC_DIALOG
1875 HWND GetLastDlgTabItem (HWND hDlg)
1880 for (HWND hSearch = GetNextDlgTabItem (hDlg, NULL, FALSE);
1881 (hSearch != NULL) && (hSearch != hFirst);
1882 hSearch = GetNextDlgTabItem (hDlg, hSearch, FALSE))
1893 BOOL IsPropSheet (HWND hSheet)
1896 if ((hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL)) == NULL)
1899 TCHAR szClassName[ cchRESOURCE ];
1900 if (!GetClassName (hTab, szClassName, cchRESOURCE))
1903 if (lstrcmp (szClassName, WC_TABCONTROL))