/* *@@sourcefile cctl_checkcnr.c: * implementation for the checkbox container common control. * See comctl.c for an overview. * * This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller]. * * Note: Version numbering in this file relates to XWorkplace version * numbering. * *@@header "helpers\comctl.h" *@@added V0.9.3 (2000-05-21) [umoeller]. */ /* * Copyright (C) 1997-2002 Ulrich M”ller. * This file is part of the "XWorkplace helpers" source package. * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, in version 2 as it comes in the * "COPYING" file of the XWorkplace main distribution. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define OS2EMX_PLAIN_CHAR // this is needed for "os2emx.h"; if this is defined, // emx will define PSZ as _signed_ char, otherwise // as unsigned char #define INCL_DOSEXCEPTIONS #define INCL_DOSPROCESS #define INCL_DOSSEMAPHORES #define INCL_DOSERRORS #define INCL_WINWINDOWMGR #define INCL_WINFRAMEMGR #define INCL_WINMESSAGEMGR #define INCL_WININPUT #define INCL_WINPOINTERS #define INCL_WINTRACKRECT #define INCL_WINTIMER #define INCL_WINSYS #define INCL_WINRECTANGLES /// xxx temporary #define INCL_WINMENUS #define INCL_WINSTATICS #define INCL_WINBUTTONS #define INCL_WINSTDCNR #define INCL_GPIPRIMITIVES #define INCL_GPILOGCOLORTABLE #define INCL_GPILCIDS #define INCL_GPIPATHS #define INCL_GPIREGIONS #define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers #include #include #include #include #include // needed for except.h #include // needed for except.h #include "setup.h" // code generation and debugging options #include "helpers\cnrh.h" #include "helpers\except.h" // exception handling #include "helpers\gpih.h" #include "helpers\linklist.h" #include "helpers\winh.h" #include "helpers\comctl.h" #pragma hdrstop /* *@@category: Helpers\PM helpers\Window classes\Checkbox containers * See cctl_checkcnr.c. */ /* ****************************************************************** * * Global variables * ********************************************************************/ // linked list of CHEXKBOXCNROWNER struct pointers HMTX G_hmtxCnrOwnersList = 0; PLINKLIST G_pllCnrOwners = 0; /* ****************************************************************** * * Checkbox container record cores * ********************************************************************/ HBITMAP G_hbmCheckboxes = NULLHANDLE; ULONG G_cxCheckbox = 0; /* *@@ ctlDrawCheckbox: * * The system checkbox bitmap (G_hbmCheckboxes) * is organized into 4 columns and three rows as * follows: * + not depressed depressed + ÚÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ¿ + checkbox ³ ³ chk ³ ³ chk ³ + ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ + radio button ³ ³ chk ³ ³ chk ³ + ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ + chbx indeterm.³ ³ ind ³ ³ ind ³ + ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ * *@@added V0.9.0 (99-11-28) [umoeller] */ BOOL ctlDrawCheckbox(HPS hps, // in: paint PS LONG x, // in: target lower left corner x LONG y, // in: target lower left corner y USHORT usRow, // in: 0 - 2 USHORT usColumn, // in: 0 - 3 BOOL fHalftoned) // in: if TRUE, the checkbox will be halftoned (grayed) { POINTL aptl[4]; BOOL brc = FALSE; if (G_hbmCheckboxes) { // paint checkbox; LONG lHits; memset(aptl, 0, sizeof(POINTL) * 4); // aptl[0]: target bottom-left aptl[0].x = x; aptl[0].y = y; // aptl[1]: target top-right (inclusive!) aptl[1].x = aptl[0].x + G_cxCheckbox - 1; aptl[1].y = aptl[0].y + G_cxCheckbox - 1; // aptl[2]: source bottom-left: // depends on record selection aptl[2].x = usColumn * G_cxCheckbox; aptl[2].y = usRow * G_cxCheckbox; // top checkbox row // aptl[3]: source top-right (non-inclusive!) aptl[3].x = aptl[2].x + G_cxCheckbox; aptl[3].y = aptl[2].y + G_cxCheckbox; if (fHalftoned) { HDC hdc = GpiQueryDevice(hps); HWND hwnd = WinWindowFromDC(hdc); HAB hab = WinQueryAnchorBlock(hwnd); HBITMAP hbmHalftoned = gpihCreateHalftonedBitmap(hab, G_hbmCheckboxes, CLR_WHITE); lHits = GpiWCBitBlt(hps, // hpsTarget hbmHalftoned, 4, &aptl[0], ROP_SRCCOPY, // mix 0); // options GpiDeleteBitmap(hbmHalftoned); } else lHits = GpiWCBitBlt(hps, // hpsTarget G_hbmCheckboxes, 4, &aptl[0], ROP_SRCCOPY, // mix 0); // options if (lHits == GPI_OK) brc = TRUE; } return brc; } /* *@@ CnrCheckboxClicked: * * *@@added V0.9.0 (99-11-28) [umoeller] */ STATIC VOID CnrCheckboxClicked(PCHECKBOXCNROWNER pcbco, PCHECKBOXRECORDCORE precc, BOOL fToggleAndNotify) // if TRUE, toggle state and notify owner (CN_RECORDCHECKED) { if (precc->ulStyle & WS_VISIBLE) { if (precc->recc.flRecordAttr & CRA_DISABLED) // disabled: WinAlarm(HWND_DESKTOP, WA_WARNING); else { if (precc->ulStyle & BS_AUTOCHECKBOX) { if (fToggleAndNotify) precc->usCheckState = 1 - precc->usCheckState; WinSendMsg(pcbco->hwndCnr, CM_INVALIDATERECORD, (MPARAM)&precc, MPFROM2SHORT(1, CMA_NOREPOSITION)); } if (fToggleAndNotify) WinPostMsg(pcbco->hwndOwner, // was: WinSendMsg WM_CONTROL, MPFROM2SHORT(pcbco->usCnrID, CN_RECORDCHECKED), (MPARAM)precc); } } } /* *@@ ctlDrawCheckBoxRecord: * *@@added V0.9.18 (2002-03-03) [umoeller] */ MRESULT ctlDrawCheckBoxRecord(MPARAM mp2) { MRESULT mrc = 0; // get generic DRAWITEM structure POWNERITEM poi = (POWNERITEM)mp2; // _Pmpf(("WM_DRAWITEM poi->idItem %d", poi->idItem)); // check if we're to draw the icon // (and not the text) if (poi->idItem == CMA_ICON) { PCNRDRAWITEMINFO pcdi = (PCNRDRAWITEMINFO)poi->hItem; PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pcdi->pRecord; if (precc->ulStyle & WS_VISIBLE) { USHORT usRow, usColumn; switch (precc->usCheckState) { case 0: // unchecked usRow = 2; usColumn = 0; break; case 1: // checked usRow = 2; usColumn = 1; break; case 2: // indeterminate usRow = 0; usColumn = 1; break; } if (precc->ulStyle & BS_BITMAP) // button currently depressed: // add two to column usColumn += 2; ctlDrawCheckbox(poi->hps, poi->rclItem.xLeft, poi->rclItem.yBottom, usRow, usColumn, // halftoned? ((precc->recc.flRecordAttr & CRA_DISABLED) != 0)); mrc = (MPARAM)FALSE; // we still need the cnr to draw the // emphasis } else mrc = (MPARAM)TRUE; // tell cnr that we've drawn the item; // don't even draw emphasis } else if (poi->idItem == CMA_TEXT) { // for text, buttons etc.: PCNRDRAWITEMINFO pcdi = (PCNRDRAWITEMINFO)poi->hItem; PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pcdi->pRecord; if (precc->recc.flRecordAttr & CRA_DISABLED) { RECTL rcl2; LONG lBackground, lForeground; ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT; if ((pcdi->pRecord->flRecordAttr) & CRA_SELECTED) { // disabled and selected: lBackground = WinQuerySysColor(HWND_DESKTOP, SYSCLR_SHADOWTEXT, 0); lForeground = winhQueryPresColor(poi->hwnd, PP_BACKGROUNDCOLOR, FALSE, // no inherit SYSCLR_WINDOW); } else { // disabled and not selected: lBackground = winhQueryPresColor(poi->hwnd, PP_BACKGROUNDCOLOR, FALSE, SYSCLR_WINDOW); lForeground = winhQueryPresColor(poi->hwnd, PP_FOREGROUNDCOLOR, FALSE, // no inherit SYSCLR_WINDOWTEXT); flCmd |= DT_HALFTONE; } // _Pmpf(("back: 0x%lX, fore: 0x%lX", lBackground, lForeground)); GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL); GpiSetBackColor(poi->hps, lBackground); GpiSetColor(poi->hps, lForeground); memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2)); winhDrawFormattedText(poi->hps, &rcl2, precc->recc.pszTree, flCmd); mrc = (MPARAM)TRUE; } else // tell cnr to draw the item mrc = (MPARAM)FALSE; } else // tell cnr to draw the item mrc = (MPARAM)FALSE; return mrc; } /* *@@ fnwpSubclCheckboxCnr: * window proc for subclassed containers. * See ctlMakeCheckboxContainer for details. * *@@added V0.9.0 (99-11-29) [umoeller] *@@changed V0.9.18 (2002-03-03) [umoeller]: fixed bad orig win msg, other optimizations *@@changed V1.0.1 (2003-01-22) [umoeller]: fixed wrong mouse pointers on WM_MOUSEMOVE */ STATIC MRESULT EXPENTRY fnwpSubclCheckboxCnr(HWND hwndCnr, ULONG msg, MPARAM mp1, MPARAM mp2) { MRESULT mrc = 0; PCHECKBOXCNROWNER pcbco = 0; PFNWP pfnwpOrig = 0; if (!DosRequestMutexSem(G_hmtxCnrOwnersList, 5000)) { PLISTNODE pNode = lstQueryFirstNode(G_pllCnrOwners); while (pNode) { pcbco = (PCHECKBOXCNROWNER)pNode->pItemData; if (pcbco->hwndCnr == hwndCnr) { pfnwpOrig = pcbco->pfnwpCnrOrig; // fixed V0.9.18 (2002-03-03) [umoeller] break; } pNode = pNode->pNext; } DosReleaseMutexSem(G_hmtxCnrOwnersList); } if (pfnwpOrig) { switch (msg) { case WM_BUTTON1DOWN: { POINTL ptlClick; ptlClick.x = SHORT1FROMMP(mp1); ptlClick.y = SHORT2FROMMP(mp1); // find record whose icon has this point pcbco->preccClicked = (PCHECKBOXRECORDCORE)cnrhFindRecordFromPoint(hwndCnr, &ptlClick, &pcbco->rclReccClicked, CMA_ICON, 0); if (pcbco->preccClicked) { if (pcbco->preccClicked->ulStyle & WS_VISIBLE) { // add "depressed" style pcbco->preccClicked->ulStyle |= BS_BITMAP; // mouse was clicked on icon (checkbox): CnrCheckboxClicked(pcbco, pcbco->preccClicked, FALSE); } else // not visible: pcbco->preccClicked = NULL; } mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); // apperently, the cnr captures the mouse } break; case WM_MOUSEMOVE: if (pcbco->preccClicked) { // mouse moved while checkbox is depressed: POINTL ptlMove; ptlMove.x = SHORT1FROMMP(mp1); ptlMove.y = SHORT2FROMMP(mp1); if (WinPtInRect(pcbco->habCnr, &pcbco->rclReccClicked, &ptlMove)) { // mouse is in checkbox: if ((pcbco->preccClicked->ulStyle & BS_BITMAP) == 0) { // checkbox is not drawn depressed: // add "depressed" style pcbco->preccClicked->ulStyle |= BS_BITMAP; CnrCheckboxClicked(pcbco, pcbco->preccClicked, FALSE); } } else { // mouse is outside of checkbox: if (pcbco->preccClicked->ulStyle & BS_BITMAP) { // checkbox is drawn depressed: // remove "depressed" style pcbco->preccClicked->ulStyle &= ~BS_BITMAP; CnrCheckboxClicked(pcbco, pcbco->preccClicked, FALSE); } } } // always call parent cos container changes mouse pointers // V1.0.1 (2003-01-22) [umoeller] mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); break; case WM_BUTTON1UP: if (pcbco->preccClicked) { if (pcbco->preccClicked->ulStyle & BS_BITMAP) { pcbco->preccClicked->ulStyle &= ~BS_BITMAP; CnrCheckboxClicked(pcbco, pcbco->preccClicked, TRUE); } pcbco->preccClicked = NULL; } mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); break; /* * WM_CHAR: * */ case WM_CHAR: { USHORT fsFlags = SHORT1FROMMP(mp1); CHAR ch = CHAR1FROMMP(mp2); // never use the USHORT, because for // the "key-up" message, the hi-char // is different (duh...) // _Pmpf(("WM_CHAR fsFlags %lX, usch %d", fsFlags, ch)); if (ch == ' ') { // space: toggle checkbox if ((fsFlags & KC_KEYUP) == 0) { // space down: // filter up repetitive key msgs if (pcbco->preccSpace == NULL) { PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)WinSendMsg( hwndCnr, CM_QUERYRECORDEMPHASIS, (MPARAM)CMA_FIRST, (MPARAM)CRA_CURSORED); if ((precc) && (precc != (PCHECKBOXRECORDCORE)-1)) { if (precc->ulStyle & WS_VISIBLE) { pcbco->preccSpace = precc; // add "depressed" style pcbco->preccSpace->ulStyle |= BS_BITMAP; CnrCheckboxClicked(pcbco, pcbco->preccSpace, FALSE); } } } } else { // space up: if (pcbco->preccSpace) { if (pcbco->preccSpace->ulStyle & BS_BITMAP) { pcbco->preccSpace->ulStyle &= ~BS_BITMAP; CnrCheckboxClicked(pcbco, pcbco->preccSpace, TRUE); } pcbco->preccSpace = NULL; } } // do not pass spaces on mrc = (MPARAM)TRUE; // processed break; } mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); } break; /* * WM_DESTROY: * remove list item; this gets sent * to the parent first, then the children, * so we remove this in the container * (this way the list item is still valid * in ctl_fnwpSubclCheckboxCnrOwner) */ case WM_DESTROY: if (!DosRequestMutexSem(G_hmtxCnrOwnersList, 5000)) { if (WinIsWindow(pcbco->habCnr, pcbco->hwndOwner)) // un-subclass the owner WinSubclassWindow(pcbco->hwndOwner, pcbco->pfnwpOwnerOrig); lstRemoveItem(G_pllCnrOwners, pcbco); if (lstCountItems(G_pllCnrOwners) == 0) lstFree(&G_pllCnrOwners); DosReleaseMutexSem(G_hmtxCnrOwnersList); } mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); break; default: mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2); } } else mrc = WinDefWindowProc(hwndCnr, msg, mp1, mp2); return mrc; } /* *@@ fnwpSubclCheckboxCnrOwner: * window proc for subclassed container owners. * See ctlMakeCheckboxContainer for details. * *@@added V0.9.0 (99-11-28) [umoeller] */ STATIC MRESULT EXPENTRY fnwpSubclCheckboxCnrOwner(HWND hwndOwner, ULONG msg, MPARAM mp1, MPARAM mp2) { MRESULT mrc = 0; PCHECKBOXCNROWNER pcbco = 0; PFNWP pfnwpOrig = 0; if (!DosRequestMutexSem(G_hmtxCnrOwnersList, 5000)) { PLISTNODE pNode = lstQueryFirstNode(G_pllCnrOwners); while (pNode) { pcbco = (PCHECKBOXCNROWNER)pNode->pItemData; if (pcbco->hwndOwner == hwndOwner) { pfnwpOrig = pcbco->pfnwpOwnerOrig; break; } pNode = pNode->pNext; } DosReleaseMutexSem(G_hmtxCnrOwnersList); } if (pfnwpOrig) { switch (msg) { /* * WM_CONTROL: * */ case WM_CONTROL: { if (SHORT1FROMMP(mp1) == pcbco->usCnrID) { switch (SHORT2FROMMP(mp1)) { case CN_ENTER: { PNOTIFYRECORDENTER pnre = (PNOTIFYRECORDENTER)mp2; PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pnre->pRecord; if (precc) CnrCheckboxClicked(pcbco, precc, TRUE); } break; default: mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2); } } else mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2); } break; /* * WM_DRAWITEM: * cnr owner draw; this is where we draw * the checkboxes */ case WM_DRAWITEM: { if (SHORT1FROMMP(mp1) == pcbco->usCnrID) mrc = ctlDrawCheckBoxRecord(mp2); else mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2); } break; default: mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2); } } else mrc = WinDefWindowProc(hwndOwner, msg, mp1, mp2); return mrc; } /* *@@ ctlQueryCheckboxSize: * *@@added V0.9.19 (2002-04-24) [umoeller] */ ULONG ctlQueryCheckboxSize(VOID) { if (G_hbmCheckboxes == NULLHANDLE) { // first call: BITMAPINFOHEADER bmih; // load checkboxes bitmap G_hbmCheckboxes = WinGetSysBitmap(HWND_DESKTOP, SBMP_CHECKBOXES); // and compute size of one checkbox // (4 columns, 3 rows) bmih.cbFix = sizeof(bmih); // V0.9.19 (2002-04-24) [umoeller] GpiQueryBitmapParameters(G_hbmCheckboxes, &bmih); G_cxCheckbox = bmih.cx / 4; } return G_cxCheckbox; } /* *@@ ctlInitCheckboxContainer: * *@@added V0.9.18 (2002-03-03) [umoeller] */ VOID ctlInitCheckboxContainer(HWND hwndCnr) { ctlQueryCheckboxSize(); BEGIN_CNRINFO() { cnrhSetView(CV_TREE | CV_ICON | CA_TREELINE | CA_OWNERDRAW | CV_MINI); cnrhSetTreeIndent(20); cnrhSetBmpOrIconSize(G_cxCheckbox, G_cxCheckbox); } END_CNRINFO(hwndCnr); } /* *@@ ctlSubclassCheckboxContainer: * *@@added V0.9.18 (2002-03-03) [umoeller] */ PCHECKBOXCNROWNER ctlSubclassCheckboxContainer(HWND hwndCnr) { PFNWP pfnwpCnrOrig; if (pfnwpCnrOrig = WinSubclassWindow(hwndCnr, fnwpSubclCheckboxCnr)) { // cnr successfully subclassed: // create storage for both subclassed cnr and owner PCHECKBOXCNROWNER pcbco; if (pcbco = (PCHECKBOXCNROWNER)malloc(sizeof(CHECKBOXCNROWNER))) { memset(pcbco, 0, sizeof(CHECKBOXCNROWNER)); pcbco->hwndCnr = hwndCnr; pcbco->usCnrID = WinQueryWindowUShort(hwndCnr, QWS_ID); pcbco->hwndOwner = WinQueryWindow(hwndCnr, QW_OWNER); pcbco->pfnwpCnrOrig = pfnwpCnrOrig; pcbco->habCnr = WinQueryAnchorBlock(hwndCnr); return pcbco; } } return NULL; } /* *@@ ctlMakeCheckboxContainer: * this turns a regular container into a "checkbox" * container. This means that the container record * icons are painted as checkboxes, whose status * is determined using an extended record core * structure (CHECKBOXRECORDCORE). * * This function assumes that all records in the * container use this special extended record core * ONLY. You cannot use regular RECORDCORE's when * using this function. Of course, you can extend * the CHECKBOXRECORDCORE structure to the bottom * if you need more fields. * * This subclasses BOTH the container and the container * owner to intercept a number of messages and to * implement owner draw. This is totally transparent * to the caller; QWL_USER is not used for this, so * you can still store your own stuff in there. * * Returns FALSE upon errors. * * To set up a checkbox container, call this function * (which switches the container to Tree view automatically). * Then, allocate and insert CHECKBOXRECORDCORE's as usual. * * To set and query a record's check state easily, use * ctlSetRecordChecked and ctlQueryRecordChecked. * * The checkboxes work almost identically to regular * checkboxes. The user can interact with the checkbox * by clicking on the checkbox itself or by double-clicking * on the record text or by pressing the Enter or Space keys. * * Set CHECKBOXRECORDCORE.ulStyle to one of the regular * checkbox button style bits; if one of the "auto" flags * is set, the checkbox is toggled automatically. * * Even if "auto" is off, when the user changes the check * box selection, hwndCnrOwner gets sent a WM_CONTROL message * with the following parameters: * * -- mp1: USHORT id: usCnrID, as passed to this func * -- mp1: USHORT usNotifyCode: CN_RECORDCHECKED (999) * -- mp2: PCHECKRECORDCORE precc: the record which was (un)checked. * * Note that the subclassed container owner proc filters out * CN_ENTER, so you'll never receive that (but CN_RECORDCHECKED * instead). * * If the "auto" style bits have not been set, you must call * ctlSetRecordChecked yourself then. * *@@added V0.9.0 (99-11-28) [umoeller] */ BOOL ctlMakeCheckboxContainer(HWND hwndCnrOwner, // in: owner (and parent) of container USHORT usCnrID) // in: ID of container in hwndCnrOwner { BOOL brc = FALSE; HWND hwndCnr = WinWindowFromID(hwndCnrOwner, usCnrID); // create mutex-protected list of container owners if (G_hmtxCnrOwnersList == 0) if (DosCreateMutexSem(NULL, &G_hmtxCnrOwnersList, 0, FALSE) != NO_ERROR) return FALSE; if (G_pllCnrOwners == NULL) G_pllCnrOwners = lstCreate(TRUE); if (hwndCnr) { ctlInitCheckboxContainer(hwndCnr); if ( (hwndCnrOwner) && (G_hmtxCnrOwnersList) ) { // subclass container owner PFNWP pfnwpOwnerOrig = WinSubclassWindow(hwndCnrOwner, fnwpSubclCheckboxCnrOwner); /* _Pmpf(("Subclassed hwnd 0x%lX: orig 0x%lX", hwndCnrOwner, pfnwpOwnerOrig)); */ if (pfnwpOwnerOrig) { // owner successfully subclassed: // subclass container too PCHECKBOXCNROWNER pcbco; if (pcbco = ctlSubclassCheckboxContainer(hwndCnr)) { if (!DosRequestMutexSem(G_hmtxCnrOwnersList, 5000)) { lstAppendItem(G_pllCnrOwners, pcbco); DosReleaseMutexSem(G_hmtxCnrOwnersList); brc = TRUE; pcbco->pfnwpOwnerOrig = pfnwpOwnerOrig; } } } } } return brc; } /* *@@ FINDCHECKRECORD: * *@@added V1.0.0 (2002-09-09) [umoeller] */ typedef struct _FINDCHECKRECORD { ULONG ulItemID; PCHECKBOXRECORDCORE precFound; } FINDCHECKRECORD, *PFINDCHECKRECORD; /* *@@ fncbFindCheckRecord: * helper callback for finding a checkbox * record according to an item ID. Used * with cnrhForAllRecords. * * Returns 1 if found to make * cnrhForAllRecords stop searching. * *@@added V0.9.0 (99-11-28) [umoeller] *@@changed V1.0.0 (2002-09-09) [umoeller]: adjusted for cnrhForAllRecords updates */ STATIC ULONG XWPENTRY fncbFindCheckRecord(HWND hwndCnr, // in: container PRECORDCORE preccThis, // in: current record (from cnrhForAllRecords) ULONG ulUser) { if (((PCHECKBOXRECORDCORE)preccThis)->ulItemID == ((PFINDCHECKRECORD)ulUser)->ulItemID) { // found: store found record ((PFINDCHECKRECORD)ulUser)->precFound = (PCHECKBOXRECORDCORE)preccThis; // and stop return 1; } return 0; } /* *@@ ctlFindCheckRecord: * this searches the given checkbox container * for the record which matches the given item * ID. Returns NULL if not found. * *@@added V0.9.1 (99-12-03) [umoeller] *@@changed V1.0.0 (2002-09-09) [umoeller]: adjusted for cnrhForAllRecords updates */ PCHECKBOXRECORDCORE ctlFindCheckRecord(HWND hwndCnr, ULONG ulItemID) { FINDCHECKRECORD fcr; fcr.ulItemID = ulItemID; fcr.precFound = NULL; cnrhForAllRecords(hwndCnr, NULL, // start with root fncbFindCheckRecord, (ULONG)&fcr); return fcr.precFound; } /* *@@ ctlSetRecordChecked: * this searches the given checkbox container * for the record which matches the given item * ID and updates that record check state. * * The check state may be: * -- 0: not checked (as with regular checkboxes) * -- 1: checked (as with regular checkboxes) * -- 2: indeterminate (as with regular checkboxes) * * Returns FALSE if the record could not be found. * *@@added V0.9.0 (99-11-28) [umoeller] */ BOOL ctlSetRecordChecked(HWND hwndCnr, // in: container prepared with // ctlMakeCheckboxContainer ULONG ulItemID, // in: record item ID USHORT usCheckState) // in: 0, 1, 2, 3 { PCHECKBOXRECORDCORE precc; if (precc = ctlFindCheckRecord(hwndCnr, ulItemID)) { precc->usCheckState = usCheckState; WinSendMsg(hwndCnr, CM_INVALIDATERECORD, (MPARAM)&precc, MPFROM2SHORT(1, CMA_NOREPOSITION)); return TRUE; } return FALSE; } /* *@@ ctlQueryRecordChecked: * this searches the given checkbox container * for the record which matches the given item * ID and returns that record's check state. * * Returns: * -- 0: not checked (as with regular checkboxes) * -- 1: checked (as with regular checkboxes) * -- 2: indeterminate (as with regular checkboxes) * -- -1: record not found. * *@@added V0.9.0 (99-11-28) [umoeller] */ ULONG ctlQueryRecordChecked(HWND hwndCnr, // in: container prepared with // ctlMakeCheckboxContainer ULONG ulItemID, // in: record item ID USHORT usCheckState) // in: 0, 1, 2, 3 { PCHECKBOXRECORDCORE precc; if (precc = ctlFindCheckRecord(hwndCnr, ulItemID)) return precc->usCheckState; return -1; } /* *@@ ctlEnableRecord: * this searches the given checkbox container * for the record which matches the given item * ID and updates that record enablement. If * the record is disabled, it's painted halftoned * by fnwpSubclCheckboxCnr. * *@@added V0.9.1 (99-12-03) [umoeller] */ BOOL ctlEnableRecord(HWND hwndCnr, ULONG ulItemID, BOOL fEnable) { PCHECKBOXRECORDCORE precc; if (precc = ctlFindCheckRecord(hwndCnr, ulItemID)) { ULONG ulAttr = precc->recc.flRecordAttr; if (fEnable) precc->recc.flRecordAttr &= ~CRA_DISABLED; else precc->recc.flRecordAttr |= CRA_DISABLED; if (precc->recc.flRecordAttr != ulAttr) // attrs changed: repaint WinSendMsg(hwndCnr, CM_INVALIDATERECORD, (MPARAM)&precc, MPFROM2SHORT(1, CMA_NOREPOSITION)); return TRUE; } return FALSE; }