Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afsapplib / dialog.cpp
blobf897a4d9826ad62b31ceab0d5f843e3da1f9b645
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
15 #include <windows.h>
16 #include <windowsx.h>
17 #include <commctrl.h>
18 #include <stdlib.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
26 #endif
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 ______________________________________________________________
36 #ifndef REALLOC
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)
40 LPVOID pNew;
41 size_t cNew;
43 if (cReq <= *pcTarget)
44 return TRUE;
46 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
47 return FALSE;
49 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
50 return FALSE;
51 memset (pNew, 0x00, cbElement * cNew);
53 if (*pcTarget != 0)
55 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
56 Free (*ppTarget);
59 *ppTarget = pNew;
60 *pcTarget = cNew;
61 return TRUE;
63 #endif
66 void DialogGetRectInParent (HWND hWnd, RECT *pr)
68 POINT pt;
70 GetWindowRect (hWnd, pr);
72 pr->right -= pr->left;
73 pr->bottom -= pr->top; // right/bottom == width/height for now
75 pt.x = pr->left;
76 pt.y = pr->top;
78 ScreenToClient (GetParent (hWnd), &pt);
80 pr->left = pt.x;
81 pr->top = pt.y;
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)
94 switch (msg)
96 case WM_NOTIFY:
97 switch (((NMHDR FAR *)lp)->code)
99 case PSN_KILLACTIVE:
100 FORWARD_WM_COMMAND (hDlg, IDOK, 0, 0, SendMessage);
101 return TRUE;
102 case PSN_APPLY:
103 FORWARD_WM_COMMAND (hDlg, IDAPPLY, 0, 0, SendMessage);
104 return TRUE;
105 case PSN_HELP:
106 FORWARD_WM_COMMAND (hDlg, IDHELP, 0, 0, SendMessage);
107 return TRUE;
108 case PSN_SETACTIVE:
109 FORWARD_WM_COMMAND (hDlg, IDINIT, wp, lp, SendMessage);
110 return TRUE;
111 case PSN_RESET:
112 FORWARD_WM_COMMAND (hDlg, IDCANCEL, 0, 0, SendMessage);
113 return TRUE;
115 break;
118 return FALSE;
122 static struct
124 BOOL fInUse;
125 HWND hSheet;
126 LPPROPSHEET psh;
127 size_t cRef;
128 } *aPropSheets = NULL;
130 static size_t cPropSheets = 0;
133 HRESULT CALLBACK PropTab_HookProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
135 if (PropSheet_HandleNotify (hDlg, msg, wp, lp))
136 return TRUE;
138 HWND hSheet = GetParent (hDlg);
139 HWND hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL);
141 if (IsWindow (hTab))
143 size_t ii;
144 for (ii = 0; ii < cPropSheets; ++ii)
146 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
147 break;
149 if (ii >= cPropSheets)
151 for (size_t ii = 0; ii < cPropSheets; ++ii)
153 if (aPropSheets[ii].fInUse && !aPropSheets[ii].hSheet)
155 aPropSheets[ii].hSheet = hSheet;
156 break;
160 if (ii < cPropSheets)
162 size_t iTab;
163 for (iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
165 if (aPropSheets[ii].psh->aTabs[iTab].hDlg == hDlg)
166 break;
168 if (iTab == aPropSheets[ii].psh->cTabs)
170 iTab = (size_t)TabCtrl_GetCurSel (hTab);
172 if (iTab < aPropSheets[ii].psh->cTabs)
174 aPropSheets[ii].psh->aTabs[iTab].hDlg = hDlg;
175 BOOL rc = (CallWindowProc ((WNDPROC)(aPropSheets[ ii ].psh->aTabs[ iTab ].dlgproc), hDlg, msg, wp, lp)?TRUE:FALSE);
177 switch (msg)
179 case WM_INITDIALOG:
180 ++ aPropSheets[ ii ].cRef;
181 break;
183 case WM_DESTROY:
184 if (!(-- aPropSheets[ ii ].cRef))
186 PropSheet_Free (aPropSheets[ ii ].psh);
187 aPropSheets[ ii ].fInUse = FALSE;
189 break;
192 return rc;
197 return DefWindowProc (hDlg, msg, wp, lp);
202 LPPROPSHEET PropSheet_Create (LONG idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
204 LPPROPSHEET psh = New (PROPSHEET);
205 memset (psh, 0x00, sizeof(PROPSHEET));
206 psh->sh.dwSize = sizeof(PROPSHEETHEADER);
207 psh->sh.dwFlags = PSH_MODELESS | ((fContextHelp) ? PSH_HASHELP : 0);
208 psh->sh.hwndParent = hParent;
209 psh->sh.hInstance = THIS_HINST;
210 psh->sh.pszCaption = (HIWORD(idsTitle)) ? (LPTSTR)(LONG_PTR)idsTitle : FormatString(TEXT("%1"),TEXT("%m"),idsTitle);
211 psh->fMadeCaption = (HIWORD(idsTitle)) ? FALSE : TRUE;
212 psh->lpUser = lp;
213 return psh;
216 LPPROPSHEET PropSheet_Create (int idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
218 return PropSheet_Create ((LONG)idsTitle, fContextHelp, hParent, lp);
221 LPPROPSHEET PropSheet_Create (LPTSTR pszTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
223 return PropSheet_Create ((LONG)(LONG_PTR)pszTitle, fContextHelp, hParent, lp);
227 BOOL PropSheet_AddTab (LPPROPSHEET psh, LONG idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
229 TCHAR szTitle[ cchRESOURCE ];
231 PROPSHEETPAGE psp;
232 memset (&psp, 0x00, sizeof(psp));
233 psp.dwSize = sizeof(PROPSHEETPAGE);
234 psp.dwFlags = PSP_DEFAULT | PSP_DLGINDIRECT | (fHelpButton ? PSP_HASHELP : 0);
235 psp.pResource = TaLocale_GetDialogResource (idd, &psp.hInstance);
236 psp.pfnDlgProc = (DLGPROC)PropTab_HookProc;
237 psp.lParam = lpUser;
239 // When first creating the PROPSHEET structure, we had to guess about
240 // which module the tabs would be coming from. Now that we have at least
241 // one tab, we can correct that guess.
243 psh->sh.hInstance = psp.hInstance;
245 if (HIWORD(idsTitle))
247 psp.pszTitle = (LPTSTR)(LONG_PTR)idsTitle;
248 psp.dwFlags |= PSP_USETITLE;
250 else if (idsTitle != 0)
252 GetString (szTitle, idsTitle);
253 psp.pszTitle = szTitle;
254 psp.dwFlags |= PSP_USETITLE;
257 HPROPSHEETPAGE hp;
258 if ((hp = CreatePropertySheetPage (&psp)) == 0)
259 return FALSE;
261 size_t size = psh->sh.nPages;
262 if (!REALLOC( psh->sh.phpage, size, 1+psh->sh.nPages, 1))
263 return FALSE;
265 psh->sh.nPages = (UINT) size;
266 if (!REALLOC( psh->aTabs, psh->cTabs, psh->sh.nPages, 1))
267 return FALSE;
269 psh->aTabs[ psh->sh.nPages-1 ].dlgproc = dlgproc;
270 psh->aTabs[ psh->sh.nPages-1 ].lpUser = lpUser;
271 psh->aTabs[ psh->sh.nPages-1 ].hDlg = 0;
273 psh->sh.phpage[ psh->sh.nPages-1 ] = hp;
274 if (fStartPage)
275 psh->sh.nStartPage = psh->sh.nPages-1;
277 return TRUE;
280 BOOL PropSheet_AddTab (LPPROPSHEET psh, int idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
282 return PropSheet_AddTab (psh, (LONG)idsTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
285 BOOL PropSheet_AddTab (LPPROPSHEET psh, LPTSTR pszTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
287 return PropSheet_AddTab (psh, (LONG)(LONG_PTR)pszTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
291 void PropSheet_NotifyAllTabs (LPPROPSHEET psh, HWND hDlg, UINT msg)
293 for (size_t ii = 0; ii < psh->cTabs; ++ii)
295 if (psh->aTabs[ ii ].dlgproc)
297 CallWindowProc ((WNDPROC)(psh->aTabs[ ii ].dlgproc), hDlg, msg, (WPARAM)psh, psh->aTabs[ ii ].lpUser);
303 HRESULT CALLBACK PropSheet_HookProc (HWND hSheet, UINT msg, WPARAM wp, LPARAM lp)
305 PVOID oldproc = Subclass_FindNextHook (hSheet, PropSheet_HookProc);
306 HRESULT rc;
308 if (oldproc)
309 rc = CallWindowProc ((WNDPROC)oldproc, hSheet, msg, wp, lp);
310 else
311 rc = DefWindowProc (hSheet, msg, wp, lp);
313 switch (msg)
315 case WM_DESTROY:
316 size_t ii;
317 for (ii = 0; ii < cPropSheets; ++ii)
319 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
320 break;
322 if (ii < cPropSheets)
324 for (size_t iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
326 if ( (aPropSheets[ii].psh->aTabs[iTab].hDlg) &&
327 (IsWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg)) &&
328 (aPropSheets[ii].psh->aTabs[iTab].dlgproc != NULL) )
330 DestroyWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg);
334 PropSheet_NotifyAllTabs (aPropSheets[ ii ].psh, hSheet, WM_DESTROY_SHEET);
336 if (!(-- aPropSheets[ ii ].cRef))
338 PropSheet_Free (aPropSheets[ ii ].psh);
339 aPropSheets[ ii ].fInUse = FALSE;
343 Subclass_RemoveHook (hSheet, PropSheet_HookProc);
344 break;
347 return rc;
351 LPARAM PropSheet_FindTabParam (HWND hTab)
353 size_t ii;
354 for (ii = 0; ii < cPropSheets; ++ii)
356 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hTab))
357 return aPropSheets[ii].psh->lpUser;
360 HWND hSheet = GetParent (hTab);
361 for (ii = 0; ii < cPropSheets; ++ii)
363 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
364 break;
366 if (ii < cPropSheets)
368 for (size_t iTab = 0; iTab < aPropSheets[ ii ].psh->cTabs; ++iTab)
370 if (hTab == aPropSheets[ ii ].psh->aTabs[ iTab ].hDlg)
371 return aPropSheets[ ii ].psh->aTabs[ iTab ].lpUser;
375 return 0;
379 BOOL PropSheet_ShowModal (LPPROPSHEET psh, void (*fnPump)(MSG *lpm))
381 HWND hSheet;
382 if ((hSheet = PropSheet_ShowModeless (psh, SW_SHOW)) == NULL)
383 return FALSE;
385 BOOL fWasEnabled = TRUE;
386 HWND hParent = psh->sh.hwndParent;
387 if (hParent && IsWindow (hParent))
389 fWasEnabled = IsWindowEnabled (hParent);
390 EnableWindow (hParent, FALSE);
393 MSG msg;
394 while (GetMessage (&msg, NULL, 0, 0))
396 if (IsMemoryManagerMessage (&msg))
397 continue;
399 if (!PropSheet_GetCurrentPageHwnd (hSheet))
401 if (hParent && IsWindow (hParent))
402 EnableWindow (hParent, fWasEnabled);
403 DestroyWindow (hSheet);
406 if (!IsWindow (hSheet))
408 if (fnPump)
409 (*fnPump)(&msg);
410 else
412 TranslateMessage (&msg);
413 DispatchMessage (&msg);
415 break;
418 if (PropSheet_IsDialogMessage (hSheet, &msg))
419 continue;
421 if (fnPump)
422 (*fnPump)(&msg);
423 else
425 TranslateMessage (&msg);
426 DispatchMessage (&msg);
430 if (hParent && IsWindow (hParent))
431 EnableWindow (hParent, fWasEnabled);
433 return TRUE;
437 HWND PropSheet_ShowModeless (LPPROPSHEET psh, int nCmdShow)
439 // Write down that we're opening a property sheet. Since we
440 // don't know the window handle yet, we'll set it to zero--
441 // when PropSheetTab_HookProc gets called for a property sheet
442 // that doesn't seem to be listed, it will write down hSheet for us.
443 // This way, we get the aPropSheets[] array filled in--complete with
444 // window handle--*before* the tabs themselves get any messages.
445 // Otherwise, we'd have to wait until the WM_INITDIALOG/IDINIT
446 // messages were finished.
448 size_t ii;
449 for (ii = 0; ii < cPropSheets; ++ii)
451 if (!aPropSheets[ ii ].fInUse)
452 break;
454 if (!REALLOC (aPropSheets, cPropSheets, 1+ii, 4))
455 return NULL;
456 aPropSheets[ ii ].fInUse = TRUE;
457 aPropSheets[ ii ].hSheet = 0;
458 aPropSheets[ ii ].psh = psh;
459 aPropSheets[ ii ].cRef = 1;
461 // Open the property sheet dialog.
463 psh->sh.dwFlags |= PSH_MODELESS;
465 HWND hSheet;
466 if ((hSheet = (HWND)PropertySheet (&psh->sh)) == NULL)
467 return NULL;
469 // Tell all tabs (not just the first one) that the sheet has been
470 // created. We'll also want to hook the sheet itself here, so we can
471 // clean up when it's destroyed.
473 Subclass_AddHook (hSheet, PropSheet_HookProc);
474 PropSheet_NotifyAllTabs (psh, hSheet, WM_INITDIALOG_SHEET);
475 ShowWindow (hSheet, nCmdShow);
477 return hSheet;
481 void PropSheet_Free (LPPROPSHEET psh)
483 if (psh)
485 if (psh->sh.phpage)
487 Free (psh->sh.phpage);
489 if (psh->fMadeCaption && psh->sh.pszCaption)
491 FreeString (psh->sh.pszCaption);
493 if (psh->aTabs)
495 Free (psh->aTabs);
498 Delete (psh);
503 HWND PropSheet_FindTabWindow (LPPROPSHEET psh, DLGPROC dlgproc)
505 if (psh)
507 for (size_t iTab = 0; iTab < psh->cTabs; ++iTab)
509 if (dlgproc == psh->aTabs[ iTab ].dlgproc)
510 return psh->aTabs[ iTab ].hDlg;
513 return NULL;
517 void PropSheetChanged (HWND hDlg)
519 PropSheet_Changed (GetParent(hDlg), hDlg);
523 void TabCtrl_SwitchToTab (HWND hTab, int iTab)
525 TabCtrl_SetCurSel (hTab, iTab);
527 NMHDR nm;
528 nm.hwndFrom = hTab;
529 nm.idFrom = IDC_PROPSHEET_TABCTRL;
530 nm.code = TCN_SELCHANGE;
531 SendMessage (GetParent (hTab), WM_NOTIFY, 0, (LPARAM)&nm);
536 * LISTVIEW ___________________________________________________________________
540 LPARAM FL_StartChange (HWND hList, BOOL fReset)
542 LPARAM dwSelected = FL_GetSelectedData (hList);
543 FastList_Begin (hList);
544 if (fReset)
545 FastList_RemoveAll (hList);
546 return dwSelected;
550 void FL_EndChange (HWND hList, LPARAM lpToSelect)
552 if (lpToSelect != 0)
553 FL_SetSelectedByData (hList, lpToSelect);
554 FastList_EndAll (hList);
558 void FL_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
560 for (WORD ii = 0; ii < nCols; ++ii)
562 FASTLISTCOLUMN flc;
563 FastList_GetColumn (hList, ii, &flc);
565 flc.cxWidth = acx[ ii ];
566 FastList_SetColumn (hList, ii, &flc);
571 void cdecl FL_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
573 va_list arg;
574 va_start (arg, acx);
576 for (WORD ii = 0; ii < nCols; ii++)
578 FASTLISTCOLUMN flc;
579 GetString (flc.szText, va_arg (arg, WORD));
580 flc.dwFlags = FLCF_JUSTIFY_LEFT;
581 flc.cxWidth = acx[ ii ]; // width of the column, in pixels
582 FastList_SetColumn (hList, ii, &flc);
587 void FL_GetColumns (HWND hList, WORD nCols, WORD *acx)
589 for (WORD ii = 0; ii < nCols; ii++)
591 FASTLISTCOLUMN flc;
592 FastList_GetColumn (hList, ii, &flc);
593 acx[ ii ] = (WORD)flc.cxWidth;
598 HLISTITEM cdecl FL_AddItem (HWND hList, WORD nCols, LPARAM lp, int iImage1, ...)
600 va_list arg;
601 va_start (arg, iImage1);
603 FASTLISTADDITEM flai;
604 memset (&flai, 0x00, sizeof(flai));
605 flai.hParent = NULL;
606 flai.iFirstImage = iImage1;
607 flai.iSecondImage = IMAGE_NOIMAGE;
608 flai.pszText = va_arg (arg, LPTSTR);
609 flai.lParam = lp;
610 flai.dwFlags = 0;
612 FastList_Begin (hList);
614 HLISTITEM hItem;
615 if ((hItem = FastList_AddItem (hList, &flai)) != NULL)
617 for (WORD ii = 1; ii < nCols; ii++)
619 FastList_SetItemText (hList, hItem, ii, va_arg (arg, LPTSTR));
623 FastList_End (hList);
624 return hItem;
628 void FL_GetItemText (HWND hList, HLISTITEM hItem, int iCol, LPTSTR psz)
630 LPCTSTR pszText = FastList_GetItemText (hList, hItem, iCol);
631 if (!pszText)
632 *psz = TEXT('\0');
633 else
634 lstrcpy (psz, pszText);
638 void FL_SetItemText (HWND hList, HLISTITEM hItem, int iCol, LPCTSTR psz)
640 FastList_SetItemText (hList, hItem, iCol, psz);
644 void FL_SetSelectedByData (HWND hList, LPARAM lp)
646 HLISTITEM hItem;
647 if ((hItem = FastList_FindItem (hList, lp)) != NULL)
649 FL_SetSelected (hList, hItem);
654 void FL_SetSelected (HWND hList, HLISTITEM hItem)
656 FastList_Begin (hList);
657 FastList_SelectNone (hList);
658 if (hItem)
660 FastList_SelectItem (hList, hItem, TRUE);
661 FastList_EnsureVisible (hList, hItem);
663 FastList_SetFocus (hList, hItem);
664 FastList_End (hList);
668 HLISTITEM FL_GetSelected (HWND hList, HLISTITEM hItem)
670 return FastList_FindNextSelected (hList, hItem);
674 HLISTITEM FL_GetFocused (HWND hList)
676 return FastList_GetFocus (hList);
680 LPARAM FL_GetFocusedData (HWND hList)
682 HLISTITEM hItem;
683 if ((hItem = FastList_GetFocus (hList)) == NULL)
684 return 0;
686 return FastList_GetItemParam (hList, hItem);
690 LPARAM FL_GetData (HWND hList, HLISTITEM hItem)
692 return FastList_GetItemParam (hList, hItem);
696 HLISTITEM FL_GetIndex (HWND hList, LPARAM lp)
698 return FastList_FindItem (hList, lp);
702 LPARAM FL_GetSelectedData (HWND hList)
704 HLISTITEM hItem;
705 if ((hItem = FastList_FindFirstSelected (hList)) == NULL)
706 return 0;
708 return FastList_GetItemParam (hList, hItem);
712 void FL_RestoreView (HWND hList, LPVIEWINFO lpvi)
714 FastList_Begin (hList);
716 for (size_t cColumns = FastList_GetColumnCount(hList); cColumns; --cColumns)
718 FastList_RemoveColumn (hList, cColumns-1);
721 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
723 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
724 continue;
726 size_t iColumn = lpvi->aColumns[ ii ];
728 FASTLISTCOLUMN flc;
729 GetString (flc.szText, lpvi->idsColumns[ iColumn ]);
731 flc.dwFlags = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? FLCF_JUSTIFY_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? FLCF_JUSTIFY_CENTER : FLCF_JUSTIFY_LEFT;
732 flc.cxWidth = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
733 FastList_SetColumn (hList, ii, &flc);
736 // Restore the fastlist's sort style
738 FastList_SetSortStyle (hList, (lpvi->iSort & (~COLUMN_SORTREV)), !!(lpvi->iSort & COLUMN_SORTREV));
740 // Switch the FastList into the proper mode--Large Icons,
741 // Small Icons, List or Details.
743 LONG dw = GetWindowLong (hList, GWL_STYLE);
744 dw &= ~FLS_VIEW_MASK;
745 dw |= lpvi->lvsView;
746 SetWindowLong (hList, GWL_STYLE, dw);
748 FastList_End (hList);
752 void FL_StoreView (HWND hList, LPVIEWINFO lpvi)
754 // First, remember what mode the the FastList is in--Large,
755 // Small, List, Tree, or TreeList.
757 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
758 lpvi->lvsView &= FLS_VIEW_MASK;
760 // Record the fastlist's sort style
762 int iCol;
763 BOOL fRev;
764 FastList_GetSortStyle (hList, &iCol, &fRev);
765 lpvi->iSort = (size_t)iCol;
766 if (fRev)
767 lpvi->iSort |= COLUMN_SORTREV;
769 // Then remember the columns' widths; we expect that the columns
770 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
771 // already.
773 if (lpvi->lvsView & FLS_VIEW_LIST)
775 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
777 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
778 continue;
780 size_t iColumn = lpvi->aColumns[ii];
782 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
784 FASTLISTCOLUMN flc;
785 FastList_GetColumn (hList, ii, &flc);
786 lpvi->cxColumns[ iColumn ] = flc.cxWidth | dwJust;
792 HLISTITEM cdecl FL_AddItem (HWND hList, LPVIEWINFO lpvi, LPARAM lp, int iImage1, ...)
794 va_list arg;
795 va_start (arg, iImage1);
797 LPTSTR apszColumns[ nCOLUMNS_MAX ];
798 size_t iColumn;
799 for (iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
801 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
804 FastList_Begin (hList);
806 HLISTITEM hItem = NULL;
807 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
809 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
810 continue;
812 if (ii == 0)
814 FASTLISTADDITEM flai;
815 memset (&flai, 0x00, sizeof(flai));
816 flai.hParent = NULL;
817 flai.iFirstImage = iImage1;
818 flai.iSecondImage = IMAGE_NOIMAGE;
819 flai.pszText = apszColumns[ iColumn ];
820 flai.lParam = lp;
821 flai.dwFlags = 0;
823 hItem = FastList_AddItem (hList, &flai);
825 else
827 FastList_SetItemText (hList, hItem, (int)ii, apszColumns[ (int)iColumn ]);
831 FastList_End (hList);
832 return hItem;
836 BOOL FL_HitTestForHeaderBar (HWND hList, POINT ptClient)
838 HWND hHeader;
839 for (hHeader = GetWindow (hList, GW_CHILD);
840 hHeader != NULL;
841 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
843 TCHAR szClassName[ cchRESOURCE ];
845 if (GetClassName (hHeader, szClassName, cchRESOURCE))
847 if (!lstrcmp (szClassName, WC_HEADER))
848 break;
852 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
854 RECT rHeader;
855 DialogGetRectInParent (hHeader, &rHeader);
856 if (PtInRect (&rHeader, ptClient))
857 return TRUE;
860 return FALSE;
866 * LISTVIEW ___________________________________________________________________
870 LPARAM LV_StartChange (HWND hList, BOOL fReset)
872 LPARAM dwSelected = LV_GetSelectedData (hList);
873 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
874 if (fReset)
875 ListView_DeleteAllItems (hList);
876 return dwSelected;
880 void LV_EndChange (HWND hList, LPARAM lpToSelect)
882 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
884 if (lpToSelect != (LPARAM)NULL)
885 LV_SetSelectedByData (hList, lpToSelect);
889 void LV_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
891 for (WORD ii = 0; ii < nCols; ++ii)
893 ListView_SetColumnWidth (hList, ii, acx[ ii ]);
897 void cdecl LV_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
899 va_list arg;
900 va_start (arg, acx);
902 for (WORD ii = 0; ii < nCols; ii++)
904 LV_COLUMN lvC;
905 TCHAR text[ cchRESOURCE ];
907 GetString (text, va_arg (arg, WORD));
909 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
910 lvC.fmt = LVCFMT_LEFT;
911 lvC.pszText = text;
912 lvC.cx = acx[ ii ]; // width of the column, in pixels
913 lvC.iSubItem = ii;
914 ListView_InsertColumn (hList, ii, &lvC);
919 void LV_GetColumns (HWND hList, WORD nCols, WORD *acx)
921 for (WORD ii = 0; ii < nCols; ii++)
923 acx[ ii ] = ListView_GetColumnWidth (hList, ii);
928 void cdecl LV_AddItem (HWND hList, WORD nCols, int index, LPARAM lp, int iImage, ...)
930 LV_ITEM lvI;
931 va_list arg;
932 va_start (arg, iImage);
934 lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
935 lvI.state = 0;
936 lvI.stateMask = 0;
937 lvI.iItem = index;
938 lvI.iSubItem = 0;
939 lvI.pszText = va_arg (arg, LPTSTR);
940 lvI.cchTextMax = cchRESOURCE;
941 lvI.iImage = iImage;
942 lvI.lParam = lp;
944 if ((index == INDEX_SORT) && (lvI.pszText != LPSTR_TEXTCALLBACK))
946 lvI.iItem = LV_PickInsertionPoint (hList, lvI.pszText);
949 DWORD dw = ListView_InsertItem (hList, &lvI);
951 for (WORD ii = 1; ii < nCols; ii++)
953 ListView_SetItemText (hList, dw, ii, va_arg (arg, LPTSTR));
958 void cdecl LV_GetItemText (HWND hList, int index, short col, LPTSTR psz)
960 *psz = TEXT('\0');
961 ListView_GetItemText (hList, index, col, (LPTSTR)psz, cchRESOURCE);
965 void cdecl LV_SetItemText (HWND hList, int index, short col, LPCTSTR psz)
967 ListView_SetItemText (hList, index, col, (LPTSTR)psz);
971 void LV_SetSelectedByData (HWND hList, LPARAM lp)
973 int index;
975 if ((index = LV_GetIndex (hList, lp)) != -1)
977 LV_SetSelected (hList, index);
982 void LV_SetSelected (HWND hList, int index)
984 ListView_EnsureVisible (hList, index, FALSE);
986 ListView_SetItemState (hList, index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
990 int LV_GetSelected (HWND hList, int index)
992 return ListView_GetNextItem (hList, index, LVNI_SELECTED);
996 int LV_GetFocused (HWND hList)
998 return ListView_GetNextItem (hList, -1, LVNI_FOCUSED);
1002 LPARAM LV_GetFocusedData (HWND hList)
1004 int idxFocus;
1006 if ((idxFocus = LV_GetFocused (hList)) == -1)
1007 return (LPARAM)0;
1009 return LV_GetData (hList, idxFocus);
1013 LPARAM LV_GetData (HWND hList, int index)
1015 LV_ITEM lvI;
1017 memset (&lvI, 0x00, sizeof(LV_ITEM));
1018 lvI.mask = LVIF_PARAM;
1019 lvI.iItem = index;
1021 if (! ListView_GetItem (hList, &lvI))
1022 return (LPARAM)0;
1024 return lvI.lParam;
1028 int LV_GetIndex (HWND hList, LPARAM lp)
1030 LV_FINDINFO lvfi;
1032 memset (&lvfi, 0x00, sizeof(lvfi));
1034 lvfi.flags = LVFI_PARAM;
1035 lvfi.lParam = lp;
1037 return ListView_FindItem (hList, -1, &lvfi);
1041 LPARAM LV_GetSelectedData (HWND hList)
1043 int index;
1045 if ((index = LV_GetSelected (hList)) == -1)
1046 return (LPARAM)0;
1048 return LV_GetData (hList, index);
1052 void LV_RestoreView (HWND hList, LPVIEWINFO lpvi)
1054 // Add columns to the listview; remember that we'll have to remove any
1055 // existing columns first.
1057 while (ListView_DeleteColumn (hList, 0))
1060 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1062 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1063 continue;
1065 size_t iColumn = lpvi->aColumns[ii];
1067 LV_COLUMN lvc;
1069 TCHAR szText[ cchRESOURCE ];
1070 GetString (szText, lpvi->idsColumns[ iColumn ]);
1072 lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
1073 lvc.fmt = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? LVCFMT_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? LVCFMT_CENTER : LVCFMT_LEFT;
1074 lvc.pszText = szText;
1075 lvc.cx = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
1076 lvc.iSubItem = (int)ii;
1077 ListView_InsertColumn (hList, ii, &lvc);
1080 // Switch the ListView into the proper mode--Large Icons,
1081 // Small Icons, List or Details.
1083 LONG dw = GetWindowLong (hList, GWL_STYLE);
1084 dw &= ~LVS_TYPEMASK;
1085 dw |= lpvi->lvsView;
1086 dw |= LVS_AUTOARRANGE;
1087 SetWindowLong (hList, GWL_STYLE, dw);
1088 ListView_Arrange (hList, LVA_DEFAULT);
1092 void LV_StoreView (HWND hList, LPVIEWINFO lpvi)
1094 // First, remember what mod the the ListView is in--Large Icons,
1095 // Small Icons, List or Details.
1097 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
1098 lpvi->lvsView &= LVS_TYPEMASK;
1100 // Then remember the columns' widths; we expect that the columns
1101 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
1102 // already.
1104 if (lpvi->lvsView == LVS_REPORT)
1106 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1108 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1109 continue;
1111 size_t iColumn = lpvi->aColumns[ii];
1113 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
1115 lpvi->cxColumns[ iColumn ] = ListView_GetColumnWidth (hList, ii);
1116 lpvi->cxColumns[ iColumn ] |= dwJust;
1122 typedef struct // VIEWSORTINFO
1124 HWND hList;
1125 LPVIEWINFO lpvi;
1126 size_t iColSort;
1127 BOOL fAscending;
1128 } VIEWSORTINFO, *LPVIEWSORTINFO;
1130 HRESULT CALLBACK LV_SortView_Numeric (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1132 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1133 TCHAR szText[ cchRESOURCE ];
1134 double d1;
1135 double d2;
1137 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1138 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1140 LV_GetItemText (lpvsi->hList, ii1, (short)lpvsi->iColSort, szText);
1141 d1 = atof (szText);
1143 LV_GetItemText (lpvsi->hList, ii2, (short)lpvsi->iColSort, szText);
1144 d2 = atof (szText);
1146 if (lpvsi->fAscending)
1147 return (HRESULT)((d2 < d1) ? -1 : (d2 == d1) ? 0 : 1);
1148 else
1149 return (HRESULT)((d1 < d2) ? -1 : (d1 == d2) ? 0 : 1);
1153 HRESULT CALLBACK LV_SortView_Alphabetic (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1155 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1156 TCHAR szText1[ cchRESOURCE ];
1157 TCHAR szText2[ cchRESOURCE ];
1159 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1160 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1162 LV_GetItemText (lpvsi->hList, ii1, (short)lpvsi->iColSort, szText1);
1163 LV_GetItemText (lpvsi->hList, ii2, (short)lpvsi->iColSort, szText2);
1165 if (lpvsi->fAscending)
1166 return lstrcmp (szText2, szText1);
1167 else
1168 return lstrcmp (szText1, szText2);
1172 void LV_SortView (HWND hList, LPVIEWINFO lpvi)
1174 size_t iColSort;
1175 for (iColSort = 0; iColSort < lpvi->nColsShown; ++iColSort)
1177 if ((lpvi->iSort & (~COLUMN_SORTREV)) == lpvi->aColumns[ iColSort ])
1178 break;
1181 if (iColSort < lpvi->nColsShown)
1183 VIEWSORTINFO vsi;
1184 vsi.hList = hList;
1185 vsi.lpvi = lpvi;
1186 vsi.iColSort = iColSort;
1187 vsi.fAscending = (lpvi->iSort & COLUMN_SORTREV) ? TRUE : FALSE;
1189 if (lpvi->cxColumns[ lpvi->iSort ] & COLUMN_RIGHTJUST)
1190 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Numeric, (LPARAM)&vsi);
1191 else
1192 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Alphabetic, (LPARAM)&vsi);
1197 void cdecl LV_AddItem (HWND hList, LPVIEWINFO lpvi, int index, LPARAM lp, int iImage, ...)
1199 va_list arg;
1200 va_start (arg, iImage);
1202 LPTSTR apszColumns[ nCOLUMNS_MAX ];
1203 size_t iColumn;
1204 for (iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
1206 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
1209 if ((index == INDEX_SORT) && (iColumn) && (apszColumns[0] != LPSTR_TEXTCALLBACK))
1211 index = LV_PickInsertionPoint (hList, apszColumns[0]);
1214 DWORD dw;
1215 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1217 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
1218 continue;
1220 if (ii == 0)
1222 LV_ITEM lvitem;
1223 lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
1224 lvitem.state = 0;
1225 lvitem.stateMask = 0;
1226 lvitem.iItem = index;
1227 lvitem.iSubItem = 0;
1228 lvitem.pszText = apszColumns[ iColumn ];
1229 lvitem.cchTextMax = cchRESOURCE;
1230 lvitem.iImage = iImage;
1231 lvitem.lParam = lp;
1233 dw = ListView_InsertItem (hList, &lvitem);
1235 else
1237 ListView_SetItemText (hList, dw, (int)ii, apszColumns[ iColumn ]);
1243 BOOL LV_HitTestForHeaderBar (HWND hList, POINT ptClient)
1245 HWND hHeader;
1246 for (hHeader = GetWindow (hList, GW_CHILD);
1247 hHeader != NULL;
1248 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
1250 TCHAR szClassName[ cchRESOURCE ];
1252 if (GetClassName (hHeader, szClassName, cchRESOURCE))
1254 if (!lstrcmp (szClassName, WC_HEADER))
1255 break;
1259 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
1261 RECT rHeader;
1262 DialogGetRectInParent (hHeader, &rHeader);
1263 if (PtInRect (&rHeader, ptClient))
1264 return TRUE;
1267 return FALSE;
1271 int LV_PickInsertionPoint (HWND hList, LPTSTR pszNewItem, int (__stdcall *fnSort)(LPCTSTR, LPCTSTR))
1273 int iItemLow = 0;
1274 int iItemHigh = ListView_GetItemCount (hList) -1;
1276 if (fnSort == 0)
1277 fnSort = lstrcmpi;
1279 while (iItemLow <= iItemHigh)
1281 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
1283 TCHAR szItemTest[ 256 ];
1284 ListView_GetItemText (hList, iItemTest, 0, szItemTest, 256);
1286 int iCompare = (*fnSort)(pszNewItem, szItemTest);
1287 if (iCompare <= 0)
1289 if ((iItemHigh = iItemTest-1) < iItemLow)
1290 return iItemHigh +1;
1292 if (iCompare >= 0)
1294 if ((iItemLow = iItemTest+1) > iItemHigh)
1295 return iItemLow;
1299 return 0;
1305 * COMBO BOXES ________________________________________________________________
1309 LPARAM CB_StartChange (HWND hCombo, BOOL fReset)
1311 LPARAM dwSelected = CB_GetSelectedData (hCombo);
1312 SendMessage (hCombo, WM_SETREDRAW, FALSE, 0);
1313 if (fReset)
1314 SendMessage (hCombo, CB_RESETCONTENT, 0, 0);
1315 return dwSelected;
1319 void CB_EndChange (HWND hCombo, LPARAM lpToSelect)
1321 SendMessage (hCombo, WM_SETREDRAW, TRUE, 0);
1323 if (lpToSelect != (LPARAM)NULL)
1324 CB_SetSelectedByData (hCombo, lpToSelect);
1328 UINT CB_AddItem (HWND hCombo, int nsz, LPARAM lp)
1330 LPTSTR psz;
1331 UINT rc;
1333 psz = FormatString (nsz);
1334 rc = CB_AddItem (hCombo, psz, lp);
1335 FreeString (psz);
1337 return rc;
1341 UINT CB_AddItem (HWND hCombo, LPCTSTR psz, LPARAM lp)
1343 UINT index;
1344 if ((index = (UINT)SendMessage (hCombo, CB_ADDSTRING, 0, (LPARAM)psz)) != (UINT)-1)
1346 SendMessage (hCombo, CB_SETITEMDATA, index, lp);
1348 return index;
1352 void CB_SetSelected (HWND hCombo, UINT index)
1354 SendMessage (hCombo, CB_SETCURSEL, index, 0);
1358 void CB_SetSelectedByData (HWND hCombo, LPARAM lpMatch)
1360 CB_SetSelected (hCombo, CB_GetIndex (hCombo, lpMatch));
1364 UINT CB_GetSelected (HWND hCombo)
1366 return (UINT)SendMessage (hCombo, CB_GETCURSEL, 0, 0);
1370 LPARAM CB_GetSelectedData (HWND hCombo)
1372 UINT index;
1374 if ((index = CB_GetSelected (hCombo)) == -1)
1375 return 0;
1377 return CB_GetData (hCombo, index);
1381 LPARAM CB_GetData (HWND hCombo, UINT index)
1383 return (LPARAM)SendMessage (hCombo, CB_GETITEMDATA, index, 0);
1387 UINT CB_GetIndex (HWND hCombo, LPARAM lpMatch)
1389 UINT idxMax = (UINT)SendMessage (hCombo, CB_GETCOUNT, 0, 0);
1391 for (UINT index = 0; index < idxMax; index++)
1393 if (SendMessage (hCombo, CB_GETITEMDATA, index, 0) == lpMatch)
1394 return index;
1397 return (UINT)-1;
1402 * LIST BOXES _________________________________________________________________
1406 LPARAM LB_StartChange (HWND hList, BOOL fReset)
1408 LPARAM dwSelected = LB_GetSelectedData (hList);
1409 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
1410 if (fReset)
1411 SendMessage (hList, LB_RESETCONTENT, 0, 0);
1412 return dwSelected;
1416 void LB_EndChange (HWND hList, LPARAM lpToSelect)
1418 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
1420 if (lpToSelect != (LPARAM)NULL)
1421 LB_SetSelectedByData (hList, lpToSelect);
1425 UINT LB_AddItem (HWND hList, int nsz, LPARAM lp)
1427 LPTSTR psz;
1428 UINT rc;
1430 psz = FormatString (nsz);
1431 rc = LB_AddItem (hList, psz, lp);
1432 FreeString (psz);
1434 return rc;
1438 UINT LB_AddItem (HWND hList, LPCTSTR psz, LPARAM lp)
1440 UINT index;
1441 if ((index = (UINT)SendMessage (hList, LB_ADDSTRING, 0, (LPARAM)psz)) != -1)
1443 SendMessage (hList, LB_SETITEMDATA, index, lp);
1445 return index;
1449 void LB_EnsureVisible (HWND hList, UINT index)
1451 int cyItem;
1452 if ((cyItem = (int)SendMessage (hList, LB_GETITEMHEIGHT, 0, 0)) != 0)
1454 RECT rClient;
1455 GetClientRect (hList, &rClient);
1456 int cWindow;
1457 if ((cWindow = cyRECT(rClient) / cyItem) == 0)
1458 cWindow = 1;
1460 int idxTop = (int)SendMessage (hList, LB_GETTOPINDEX, 0, 0);
1461 if (index < (UINT)idxTop)
1463 SendMessage (hList, LB_SETTOPINDEX, index, 0);
1465 else if (index >= (UINT)(idxTop +cWindow))
1467 SendMessage (hList, LB_SETTOPINDEX, index -cWindow +1, 0);
1473 void LB_SetSelected (HWND hList, UINT index)
1475 SendMessage (hList, LB_SETCURSEL, index, 0);
1476 LB_EnsureVisible (hList, index);
1480 void LB_SetSelectedByData (HWND hList, LPARAM lpMatch)
1482 LB_SetSelected (hList, LB_GetIndex (hList, lpMatch));
1486 UINT LB_GetSelected (HWND hList)
1488 return (UINT)SendMessage (hList, LB_GETCURSEL, 0, 0);
1492 LPARAM LB_GetSelectedData (HWND hList)
1494 UINT index;
1496 if ((index = LB_GetSelected (hList)) == (UINT)-1)
1497 return 0;
1499 return LB_GetData (hList, index);
1503 LPARAM LB_GetData (HWND hList, UINT index)
1505 return (LPARAM)SendMessage (hList, LB_GETITEMDATA, index, 0);
1509 UINT LB_GetIndex (HWND hList, LPARAM lpMatch)
1511 UINT idxMax = (UINT)SendMessage (hList, LB_GETCOUNT, 0, 0);
1513 for (UINT index = 0; index < idxMax; index++)
1515 if (SendMessage (hList, LB_GETITEMDATA, index, 0) == lpMatch)
1516 return index;
1519 return (UINT)-1;
1523 WORD LB_GetStringExtent (HWND hList, LPTSTR pszString)
1525 HDC hdc = GetDC (hList);
1527 SIZE sz;
1528 GetTextExtentPoint32 (hdc, pszString, lstrlen(pszString), &sz);
1530 ReleaseDC (hList, hdc);
1531 return (WORD)( sz.cx + 2 * GetSystemMetrics (SM_CXBORDER) );
1535 HRESULT CALLBACK ListBox_HScrollHook (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
1537 PVOID oldProc = Subclass_FindNextHook (hList, ListBox_HScrollHook);
1539 switch (msg)
1541 case WM_DESTROY:
1542 Subclass_RemoveHook (hList, ListBox_HScrollHook);
1543 break;
1545 case LB_ADDSTRING:
1547 LPTSTR pszString = (LPTSTR)lp;
1548 WORD cxString = LB_GetStringExtent (hList, pszString);
1549 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1550 if (cxString > cxExtent)
1551 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxString, 0);
1553 break;
1555 case LB_DELETESTRING:
1557 int iItemSkip = (int)wp;
1558 int iItemMax = (int)SendMessage (hList, LB_GETCOUNT, 0, 0);
1559 int cchMax = 0;
1560 int iItem;
1562 for (iItem = 0; iItem < iItemMax; iItem++)
1564 if (iItem == iItemSkip)
1565 continue;
1566 int cch = (int)SendMessage (hList, LB_GETTEXTLEN, (WPARAM)iItem, 0);
1567 cchMax = max (cch, cchMax);
1570 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1571 WORD cxStringMax = 0;
1572 LPTSTR pszString = AllocateString (cchMax +1);
1574 for (iItem = 0; iItem < iItemMax; iItem++)
1576 if (iItem == iItemSkip)
1577 continue;
1578 SendMessage (hList, LB_GETTEXT, (WPARAM)iItem, (LPARAM)pszString);
1579 WORD cxString = LB_GetStringExtent (hList, pszString);
1580 cxStringMax = max (cxString, cxStringMax);
1583 FreeString (pszString);
1584 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxStringMax, 0);
1586 break;
1589 if (oldProc)
1590 return CallWindowProc ((WNDPROC)oldProc, hList, msg, wp, lp);
1591 else
1592 return DefWindowProc (hList, msg, wp, lp);
1596 void LB_EnableHScroll (HWND hList)
1598 Subclass_AddHook (hList, ListBox_HScrollHook);
1603 * TREEVIEWS __________________________________________________________________
1607 LPARAM TV_GetData (HWND hTree, HTREEITEM hti)
1609 TV_ITEM tvi;
1610 tvi.lParam = 0;
1611 tvi.hItem = hti;
1612 tvi.mask = TVIF_PARAM;
1614 if (!TreeView_GetItem (hTree, &tvi))
1615 return (LPARAM)NULL;
1617 return tvi.lParam;
1621 LPARAM TV_GetSelectedData (HWND hTree)
1623 HTREEITEM hti = TreeView_GetSelection (hTree);
1625 if (hti == NULL)
1626 return NULL;
1628 return TV_GetData (hTree, hti);
1632 LPARAM TV_StartChange (HWND hTree, BOOL fReset)
1634 LPARAM dwSelected = TV_GetSelectedData (hTree);
1635 SendMessage (hTree, WM_SETREDRAW, FALSE, 0);
1636 if (fReset)
1637 TreeView_DeleteAllItems (hTree);
1638 return dwSelected;
1642 void TV_EndChange (HWND hTree, LPARAM lpToSelect)
1644 SendMessage (hTree, WM_SETREDRAW, TRUE, 0);
1646 if (lpToSelect != NULL)
1648 HTREEITEM hti = TV_RecursiveFind (hTree, TVI_ROOT, lpToSelect);
1649 if (hti != NULL)
1650 TreeView_SelectItem (hTree, hti);
1655 HTREEITEM TV_RecursiveFind (HWND hTree, HTREEITEM htiRoot, LPARAM lpToFind)
1657 for (HTREEITEM hti = (htiRoot == TVI_ROOT) ? TreeView_GetRoot (hTree) : TreeView_GetChild (hTree, htiRoot);
1658 hti != NULL;
1659 hti = TreeView_GetNextSibling (hTree, hti))
1661 if (lpToFind == TV_GetData (hTree, hti))
1662 return hti;
1664 HTREEITEM htiFound;
1665 if ((htiFound = TV_RecursiveFind (hTree, hti, lpToFind)) != NULL)
1666 return htiFound;
1669 return NULL;
1674 * COMMON DIALOGS _____________________________________________________________
1678 BOOL Browse_Open (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1680 TCHAR szFilter[ cchRESOURCE ];
1681 GetString (szFilter, idsFilter);
1682 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1683 for (LPTSTR pszFilter = szFilter;
1684 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1685 ++pszFilter)
1687 *pszFilter = TEXT('\0');
1690 OPENFILENAME ofn;
1691 memset (&ofn, 0x00, sizeof(ofn));
1692 ofn.lStructSize = sizeof(ofn);
1693 ofn.hwndOwner = hParent;
1694 ofn.hInstance = THIS_HINST;
1695 ofn.lpstrFilter = szFilter;
1696 ofn.nFilterIndex = 1;
1697 ofn.lpstrFile = pszFilename;
1698 ofn.nMaxFile = MAX_PATH;
1699 ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
1700 ofn.lCustData = lCustData;
1702 if (iddTemplate != 0)
1704 ofn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1705 ofn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1707 if (lpfnHook != NULL)
1709 ofn.lpfnHook = lpfnHook;
1710 ofn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1713 TCHAR szPath[ MAX_PATH ];
1714 GetCurrentDirectory (MAX_PATH, szPath);
1715 if (pszLastDirectory && *pszLastDirectory)
1716 SetCurrentDirectory (pszLastDirectory);
1718 BOOL rc = GetOpenFileName (&ofn);
1720 if (pszLastDirectory)
1721 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1722 SetCurrentDirectory (szPath);
1724 return rc;
1728 BOOL Browse_Save (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1730 TCHAR szFilter[ cchRESOURCE ];
1731 GetString (szFilter, idsFilter);
1732 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1733 for (LPTSTR pszFilter = szFilter;
1734 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1735 ++pszFilter)
1737 *pszFilter = TEXT('\0');
1740 OPENFILENAME sfn;
1741 memset (&sfn, 0x00, sizeof(sfn));
1742 sfn.lStructSize = sizeof(sfn);
1743 sfn.hwndOwner = hParent;
1744 sfn.hInstance = THIS_HINST;
1745 sfn.lpstrFilter = szFilter;
1746 sfn.nFilterIndex = 1;
1747 sfn.lpstrFile = pszFilename;
1748 sfn.nMaxFile = MAX_PATH;
1749 sfn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
1750 sfn.lCustData = lCustData;
1752 if (iddTemplate != 0)
1754 sfn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1755 sfn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1757 if (lpfnHook != NULL)
1759 sfn.lpfnHook = lpfnHook;
1760 sfn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1763 TCHAR szPath[ MAX_PATH ];
1764 GetCurrentDirectory (MAX_PATH, szPath);
1765 if (pszLastDirectory && *pszLastDirectory)
1766 SetCurrentDirectory (pszLastDirectory);
1768 BOOL rc = GetSaveFileName (&sfn);
1770 if (pszLastDirectory)
1771 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1772 SetCurrentDirectory (szPath);
1774 return rc;
1779 * HOURGLASS CURSOR ETC _______________________________________________________
1783 static LONG nHourGlassRequests = 0;
1785 void StartHourGlass (void)
1787 if ((++nHourGlassRequests) == 1)
1789 SetCursor (LoadCursor (NULL, IDC_WAIT));
1793 void StopHourGlass (void)
1795 if ((nHourGlassRequests == 0) || ((--nHourGlassRequests) == 0))
1797 SetCursor (LoadCursor (NULL, IDC_ARROW));
1803 void DisplayContextMenu (HMENU hm, POINT ptScreen, HWND hParent)
1805 HMENU hmDummy = CreateMenu();
1806 InsertMenu (hmDummy, 0, MF_POPUP, (UINT)(UINT_PTR)hm, NULL);
1808 TrackPopupMenu (GetSubMenu (hmDummy, 0),
1809 TPM_LEFTALIGN | TPM_RIGHTBUTTON,
1810 ptScreen.x, ptScreen.y,
1811 0, hParent, NULL);
1813 DestroyMenu (hmDummy);
1817 size_t CountChildren (HWND hParent, LPTSTR pszClass)
1819 size_t nFound = 0;
1821 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1822 hChild != NULL;
1823 hChild = GetWindow (hChild, GW_HWNDNEXT))
1825 TCHAR szClassName[ cchRESOURCE ];
1827 if (GetClassName (hChild, szClassName, cchRESOURCE))
1829 if (!lstrcmp (szClassName, pszClass))
1830 ++nFound;
1834 return nFound;
1838 WORD NextControlID (HWND hParent)
1840 WORD wNext = 1;
1842 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1843 hChild != NULL;
1844 hChild = GetWindow (hChild, GW_HWNDNEXT))
1846 LONG wChild = GetWindowLong (hChild, GWL_ID);
1847 if ((wChild < 0) || (wChild >= 0xF000))
1848 continue;
1850 wNext = max( wNext, (WORD) wChild+1 );
1853 return wNext;
1857 BOOL IsAncestor (HWND hParent, HWND hChild)
1859 for ( ; hChild; hChild = GetParent(hChild))
1861 if (hParent == hChild)
1862 return TRUE;
1864 return FALSE;
1868 HWND GetTabChild (HWND hTab)
1870 for (HWND hChild = GetWindow (hTab, GW_CHILD);
1871 hChild != NULL;
1872 hChild = GetWindow (hChild, GW_HWNDNEXT))
1874 TCHAR szClassName[ cchRESOURCE ];
1876 if (GetClassName (hChild, szClassName, cchRESOURCE))
1878 if (!lstrcmp (szClassName, TEXT("#32770"))) // WC_DIALOG
1879 return hChild;
1883 return NULL;
1887 HWND GetLastDlgTabItem (HWND hDlg)
1889 HWND hFirst = NULL;
1890 HWND hLast = NULL;
1892 for (HWND hSearch = GetNextDlgTabItem (hDlg, NULL, FALSE);
1893 (hSearch != NULL) && (hSearch != hFirst);
1894 hSearch = GetNextDlgTabItem (hDlg, hSearch, FALSE))
1896 if (!hFirst)
1897 hFirst = hSearch;
1898 hLast = hSearch;
1901 return hLast;
1905 BOOL IsPropSheet (HWND hSheet)
1907 HWND hTab;
1908 if ((hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL)) == NULL)
1909 return FALSE;
1911 TCHAR szClassName[ cchRESOURCE ];
1912 if (!GetClassName (hTab, szClassName, cchRESOURCE))
1913 return FALSE;
1915 if (lstrcmp (szClassName, WC_TABCONTROL))
1916 return FALSE;
1918 return TRUE;