home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
xwphescr.zip
/
XWPH0208.ZIP
/
src
/
helpers
/
cctl_checkcnr.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-08-08
|
35KB
|
1,023 lines
/*
*@@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 <os2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h> // needed for except.h
#include <assert.h> // 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
*/
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);
}
}
}
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;
}
/*
*@@ 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]
*/
static ULONG EXPENTRY fncbFindCheckRecord(HWND hwndCnr, // in: container
PRECORDCORE preccThis, // in: current record (from cnrhForAllRecords)
ULONG ulItemID, // in: item ID to find
ULONG ulppRecc) // out: PRECORDCORE* if found
{
ULONG ulrc = 0;
PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)preccThis;
if (precc)
{
if (precc->ulItemID == ulItemID)
{
// found:
PCHECKBOXRECORDCORE *pprecc = (PCHECKBOXRECORDCORE*)ulppRecc;
// store
*pprecc = precc;
// and stop
ulrc = 1;
}
}
return ulrc;
}
/*
*@@ 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]
*/
PCHECKBOXRECORDCORE ctlFindCheckRecord(HWND hwndCnr,
ULONG ulItemID)
{
PCHECKBOXRECORDCORE precc = 0;
cnrhForAllRecords(hwndCnr,
NULL, // start with root
fncbFindCheckRecord,
(ULONG)ulItemID, // input
(ULONG)&precc);
return precc;
}
/*
*@@ 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;
}