source: trunk/src/helpers/cctl_checkcnr.c@ 52

Last change on this file since 52 was 52, checked in by umoeller, 24 years ago

misc. changes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 KB
Line 
1
2/*
3 *@@sourcefile cctl_checkcnr.c:
4 * implementation for the checkbox container common control.
5 * See comctl.c for an overview.
6 *
7 * This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller].
8 *
9 * Note: Version numbering in this file relates to XWorkplace version
10 * numbering.
11 *
12 *@@header "helpers\comctl.h"
13 *@@added V0.9.3 (2000-05-21) [umoeller].
14 */
15
16/*
17 * Copyright (C) 1997-2000 Ulrich M”ller.
18 * This file is part of the "XWorkplace helpers" source package.
19 * This is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published
21 * by the Free Software Foundation, in version 2 as it comes in the
22 * "COPYING" file of the XWorkplace main distribution.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 */
28
29#define OS2EMX_PLAIN_CHAR
30 // this is needed for "os2emx.h"; if this is defined,
31 // emx will define PSZ as _signed_ char, otherwise
32 // as unsigned char
33
34#define INCL_DOSEXCEPTIONS
35#define INCL_DOSPROCESS
36#define INCL_DOSSEMAPHORES
37#define INCL_DOSERRORS
38
39#define INCL_WINWINDOWMGR
40#define INCL_WINFRAMEMGR
41#define INCL_WINMESSAGEMGR
42#define INCL_WININPUT
43#define INCL_WINPOINTERS
44#define INCL_WINTRACKRECT
45#define INCL_WINTIMER
46#define INCL_WINSYS
47
48#define INCL_WINRECTANGLES /// xxx temporary
49
50#define INCL_WINMENUS
51#define INCL_WINSTATICS
52#define INCL_WINBUTTONS
53#define INCL_WINSTDCNR
54
55#define INCL_GPIPRIMITIVES
56#define INCL_GPILOGCOLORTABLE
57#define INCL_GPILCIDS
58#define INCL_GPIPATHS
59#define INCL_GPIREGIONS
60#define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers
61#include <os2.h>
62
63#include <stdlib.h>
64#include <stdio.h>
65#include <string.h>
66#include <setjmp.h> // needed for except.h
67#include <assert.h> // needed for except.h
68
69#include "setup.h" // code generation and debugging options
70
71#include "helpers\cnrh.h"
72#include "helpers\except.h" // exception handling
73#include "helpers\gpih.h"
74#include "helpers\linklist.h"
75#include "helpers\winh.h"
76
77#include "helpers\comctl.h"
78
79#pragma hdrstop
80
81/*
82 *@@category: Helpers\PM helpers\Window classes\Checkbox containers
83 * See cctl_checkcnr.c.
84 */
85
86/* ******************************************************************
87 *
88 * Global variables
89 *
90 ********************************************************************/
91
92// linked list of CHEXKBOXCNROWNER struct pointers
93HMTX G_hmtxCnrOwnersList = 0;
94PLINKLIST G_pllCnrOwners = 0;
95
96/* ******************************************************************
97 *
98 * Checkbox container record cores
99 *
100 ********************************************************************/
101
102HBITMAP G_hbmCheckboxes = NULLHANDLE;
103ULONG G_cxCheckbox = 0;
104
105/*
106 *@@ ctlDrawCheckbox:
107 *
108 * The system checkbox bitmap (G_hbmCheckboxes)
109 * is organized into 4 columns and three rows as
110 * follows:
111 *
112 + not depressed depressed
113 + ÚÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ¿
114 + checkbox ³ ³ chk ³ ³ chk ³
115 + ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄŽ
116 + radio button ³ ³ chk ³ ³ chk ³
117 + ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄŽ
118 + chbx indeterm.³ ³ ind ³ ³ ind ³
119 + ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ
120 *
121 *@@added V0.9.0 (99-11-28) [umoeller]
122 */
123
124BOOL ctlDrawCheckbox(HPS hps, // in: paint PS
125 LONG x, // in: target lower left corner x
126 LONG y, // in: target lower left corner y
127 USHORT usRow, // in: 0 - 2
128 USHORT usColumn, // in: 0 - 3
129 BOOL fHalftoned) // in: if TRUE, the checkbox will be halftoned (grayed)
130{
131 POINTL aptl[4];
132 BOOL brc = FALSE;
133
134 if (G_hbmCheckboxes)
135 {
136 // paint checkbox;
137 LONG lHits;
138
139 memset(aptl, 0, sizeof(POINTL) * 4);
140
141 // aptl[0]: target bottom-left
142 aptl[0].x = x;
143 aptl[0].y = y;
144
145 // aptl[1]: target top-right (inclusive!)
146 aptl[1].x = aptl[0].x + G_cxCheckbox - 1;
147 aptl[1].y = aptl[0].y + G_cxCheckbox - 1;
148
149 // aptl[2]: source bottom-left:
150 // depends on record selection
151 aptl[2].x = usColumn * G_cxCheckbox;
152 aptl[2].y = usRow * G_cxCheckbox; // top checkbox row
153
154 // aptl[3]: source top-right (non-inclusive!)
155 aptl[3].x = aptl[2].x + G_cxCheckbox;
156 aptl[3].y = aptl[2].y + G_cxCheckbox;
157
158 if (fHalftoned)
159 {
160 HDC hdc = GpiQueryDevice(hps);
161 HWND hwnd = WinWindowFromDC(hdc);
162 HAB hab = WinQueryAnchorBlock(hwnd);
163 HBITMAP hbmHalftoned = gpihCreateHalftonedBitmap(hab,
164 G_hbmCheckboxes,
165 CLR_WHITE);
166 lHits = GpiWCBitBlt(hps, // hpsTarget
167 hbmHalftoned,
168 4,
169 &aptl[0],
170 ROP_SRCCOPY, // mix
171 0); // options
172 GpiDeleteBitmap(hbmHalftoned);
173 }
174 else
175 lHits = GpiWCBitBlt(hps, // hpsTarget
176 G_hbmCheckboxes,
177 4,
178 &aptl[0],
179 ROP_SRCCOPY, // mix
180 0); // options
181 if (lHits == GPI_OK)
182 brc = TRUE;
183 }
184
185 return (brc);
186}
187
188/*
189 *@@ CHECKBOXCNROWNER:
190 *
191 *
192 *@@added V0.9.0 (99-11-28) [umoeller]
193 */
194
195typedef struct _CHECKBOXCNROWNER
196{
197 HWND hwndCnr; // container window handle
198 USHORT usCnrID; // container item ID
199 HWND hwndOwner; // owner of that container
200 PFNWP pfnwpCnrOrig; // original window proc of hwndCnr
201 PFNWP pfnwpOwnerOrig; // original window proc of hwndOwner
202
203 HAB habCnr;
204
205 PCHECKBOXRECORDCORE preccClicked; // != NULL if mb1 is currently down on recc
206 PCHECKBOXRECORDCORE preccSpace; // != NULL if space key is down with recc
207 RECTL rclReccClicked; // rectangle of that record
208} CHECKBOXCNROWNER, *PCHECKBOXCNROWNER;
209
210/*
211 *@@ CnrCheckboxClicked:
212 *
213 *
214 *@@added V0.9.0 (99-11-28) [umoeller]
215 */
216
217VOID CnrCheckboxClicked(PCHECKBOXCNROWNER pcbco,
218 PCHECKBOXRECORDCORE precc,
219 BOOL fToggleAndNotify) // if TRUE, toggle state and notify owner (CN_RECORDCHECKED)
220{
221 if (precc->ulStyle & WS_VISIBLE)
222 {
223 if (precc->recc.flRecordAttr & CRA_DISABLED)
224 // disabled:
225 WinAlarm(HWND_DESKTOP, WA_WARNING);
226 else
227 {
228 if (precc->ulStyle & BS_AUTOCHECKBOX)
229 {
230 if (fToggleAndNotify)
231 precc->usCheckState = 1 - precc->usCheckState;
232
233 WinSendMsg(pcbco->hwndCnr,
234 CM_INVALIDATERECORD,
235 (MPARAM)&precc,
236 MPFROM2SHORT(1,
237 CMA_NOREPOSITION));
238 }
239
240 if (fToggleAndNotify)
241 WinPostMsg(pcbco->hwndOwner, // was: WinSendMsg
242 WM_CONTROL,
243 MPFROM2SHORT(pcbco->usCnrID,
244 CN_RECORDCHECKED),
245 (MPARAM)precc);
246 }
247 }
248}
249
250/*
251 *@@ ctl_fnwpSubclCheckboxCnr:
252 * window proc for subclassed containers.
253 * See ctlMakeCheckboxContainer for details.
254 *
255 *@@added V0.9.0 (99-11-29) [umoeller]
256 */
257
258MRESULT EXPENTRY ctl_fnwpSubclCheckboxCnr(HWND hwndCnr, ULONG msg, MPARAM mp1, MPARAM mp2)
259{
260 MRESULT mrc = 0;
261 PCHECKBOXCNROWNER pcbco = 0;
262 PFNWP pfnwpOrig = 0;
263
264 if (WinRequestMutexSem(G_hmtxCnrOwnersList, 5000) == NO_ERROR)
265 {
266 PLISTNODE pNode = lstQueryFirstNode(G_pllCnrOwners);
267 while (pNode)
268 {
269 pcbco = (PCHECKBOXCNROWNER)pNode->pItemData;
270 if (pcbco->hwndCnr == hwndCnr)
271 {
272 pfnwpOrig = pcbco->pfnwpOwnerOrig;
273 break;
274 }
275 pNode = pNode->pNext;
276 }
277 DosReleaseMutexSem(G_hmtxCnrOwnersList);
278 }
279
280 if (pfnwpOrig)
281 {
282 switch (msg)
283 {
284 case WM_BUTTON1DOWN:
285 {
286 POINTL ptlClick;
287 ptlClick.x = SHORT1FROMMP(mp1);
288 ptlClick.y = SHORT2FROMMP(mp1);
289
290 // find record whose icon has this point
291 pcbco->preccClicked
292 = (PCHECKBOXRECORDCORE)cnrhFindRecordFromPoint(hwndCnr,
293 &ptlClick,
294 &pcbco->rclReccClicked,
295 CMA_ICON,
296 0);
297
298 if (pcbco->preccClicked)
299 {
300 if (pcbco->preccClicked->ulStyle & WS_VISIBLE)
301 {
302 // add "depressed" style
303 pcbco->preccClicked->ulStyle |= BS_BITMAP;
304 // mouse was clicked on icon (checkbox):
305 CnrCheckboxClicked(pcbco,
306 pcbco->preccClicked,
307 FALSE);
308 }
309 else
310 // not visible:
311 pcbco->preccClicked = NULL;
312 }
313
314 mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2);
315 // apperently, the cnr captures the mouse
316 break; }
317
318 case WM_MOUSEMOVE:
319 if (pcbco->preccClicked)
320 {
321 // mouse moved while checkbox is depressed:
322 POINTL ptlMove;
323 ptlMove.x = SHORT1FROMMP(mp1);
324 ptlMove.y = SHORT2FROMMP(mp1);
325
326 if (WinPtInRect(pcbco->habCnr,
327 &pcbco->rclReccClicked,
328 &ptlMove))
329 {
330 // mouse is in checkbox:
331 if ((pcbco->preccClicked->ulStyle & BS_BITMAP) == 0)
332 {
333 // checkbox is not drawn depressed:
334 // add "depressed" style
335 pcbco->preccClicked->ulStyle |= BS_BITMAP;
336 CnrCheckboxClicked(pcbco,
337 pcbco->preccClicked,
338 FALSE);
339 }
340 }
341 else
342 {
343 // mouse is outside of checkbox:
344 if (pcbco->preccClicked->ulStyle & BS_BITMAP)
345 {
346 // checkbox is drawn depressed:
347 // remove "depressed" style
348 pcbco->preccClicked->ulStyle &= ~BS_BITMAP;
349 CnrCheckboxClicked(pcbco,
350 pcbco->preccClicked,
351 FALSE);
352 }
353 }
354 }
355 break;
356
357 case WM_BUTTON1UP:
358 if (pcbco->preccClicked)
359 {
360 if (pcbco->preccClicked->ulStyle & BS_BITMAP)
361 {
362 pcbco->preccClicked->ulStyle &= ~BS_BITMAP;
363 CnrCheckboxClicked(pcbco,
364 pcbco->preccClicked,
365 TRUE);
366 }
367
368 pcbco->preccClicked = NULL;
369 }
370 mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2);
371 break;
372
373 /*
374 * WM_CHAR:
375 *
376 */
377
378 case WM_CHAR:
379 {
380 USHORT fsFlags = SHORT1FROMMP(mp1);
381 CHAR ch = CHAR1FROMMP(mp2);
382 // never use the USHORT, because for
383 // the "key-up" message, the hi-char
384 // is different (duh...)
385
386 // _Pmpf(("WM_CHAR fsFlags %lX, usch %d", fsFlags, ch));
387
388 if (ch == ' ')
389 {
390 // space: toggle checkbox
391 if ((fsFlags & KC_KEYUP) == 0)
392 {
393 // space down:
394 // filter up repetitive key msgs
395 if (pcbco->preccSpace == NULL)
396 {
397 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)WinSendMsg(
398 hwndCnr,
399 CM_QUERYRECORDEMPHASIS,
400 (MPARAM)CMA_FIRST,
401 (MPARAM)CRA_CURSORED);
402 if ((precc) && (precc != (PCHECKBOXRECORDCORE)-1))
403 {
404 if (precc->ulStyle & WS_VISIBLE)
405 {
406 pcbco->preccSpace = precc;
407
408 // add "depressed" style
409 pcbco->preccSpace->ulStyle |= BS_BITMAP;
410 CnrCheckboxClicked(pcbco,
411 pcbco->preccSpace,
412 FALSE);
413 }
414 }
415 }
416 }
417 else
418 {
419 // space up:
420 if (pcbco->preccSpace)
421 {
422 if (pcbco->preccSpace->ulStyle & BS_BITMAP)
423 {
424 pcbco->preccSpace->ulStyle &= ~BS_BITMAP;
425 CnrCheckboxClicked(pcbco,
426 pcbco->preccSpace,
427 TRUE);
428 }
429
430 pcbco->preccSpace = NULL;
431 }
432 }
433
434 // do not pass spaces on
435 mrc = (MPARAM)TRUE; // processed
436 break;
437 }
438
439 mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2);
440 break; }
441
442 /*
443 * WM_DESTROY:
444 * remove list item; this gets sent
445 * to the parent first, then the children,
446 * so we remove this in the container
447 * (this way the list item is still valid
448 * in ctl_fnwpSubclCheckboxCnrOwner)
449 */
450
451 case WM_DESTROY:
452 if (WinRequestMutexSem(G_hmtxCnrOwnersList, 5000) == NO_ERROR)
453 {
454 lstRemoveItem(G_pllCnrOwners, pcbco);
455 if (lstCountItems(G_pllCnrOwners) == 0)
456 {
457 lstFree(G_pllCnrOwners);
458 G_pllCnrOwners = NULL;
459 }
460 DosReleaseMutexSem(G_hmtxCnrOwnersList);
461 }
462
463 mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2);
464 break;
465
466 default:
467 mrc = pfnwpOrig(hwndCnr, msg, mp1, mp2);
468 }
469 }
470 else
471 mrc = WinDefWindowProc(hwndCnr, msg, mp1, mp2);
472
473 return (mrc);
474}
475
476
477/*
478 *@@ ctl_fnwpSubclCheckboxCnrOwner:
479 * window proc for subclassed container owners.
480 * See ctlMakeCheckboxContainer for details.
481 *
482 *@@added V0.9.0 (99-11-28) [umoeller]
483 */
484
485MRESULT EXPENTRY ctl_fnwpSubclCheckboxCnrOwner(HWND hwndOwner, ULONG msg, MPARAM mp1, MPARAM mp2)
486{
487 MRESULT mrc = 0;
488 PCHECKBOXCNROWNER pcbco = 0;
489 PFNWP pfnwpOrig = 0;
490
491 if (WinRequestMutexSem(G_hmtxCnrOwnersList, 5000) == NO_ERROR)
492 {
493 PLISTNODE pNode = lstQueryFirstNode(G_pllCnrOwners);
494 while (pNode)
495 {
496 pcbco = (PCHECKBOXCNROWNER)pNode->pItemData;
497 if (pcbco->hwndOwner == hwndOwner)
498 {
499 pfnwpOrig = pcbco->pfnwpOwnerOrig;
500 break;
501 }
502 pNode = pNode->pNext;
503 }
504 DosReleaseMutexSem(G_hmtxCnrOwnersList);
505 }
506
507 if (pfnwpOrig)
508 {
509 switch (msg)
510 {
511 /*
512 * WM_CONTROL:
513 *
514 */
515
516 case WM_CONTROL:
517 {
518 USHORT usItemID = SHORT1FROMMP(mp1),
519 usNotifyCode = SHORT2FROMMP(mp1);
520
521 if (usItemID == pcbco->usCnrID)
522 {
523 switch (usNotifyCode)
524 {
525 case CN_ENTER:
526 {
527 PNOTIFYRECORDENTER pnre = (PNOTIFYRECORDENTER)mp2;
528 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pnre->pRecord;
529
530 if (precc)
531 CnrCheckboxClicked(pcbco,
532 precc,
533 TRUE);
534 break; }
535 }
536 }
537
538 mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2);
539 break; }
540
541 /*
542 * WM_DRAWITEM:
543 * cnr owner draw; this is where we draw
544 * the checkboxes
545 */
546
547 case WM_DRAWITEM:
548 {
549 USHORT usID = SHORT1FROMMP(mp1);
550 if (usID == pcbco->usCnrID)
551 {
552 // get generic DRAWITEM structure
553 POWNERITEM poi = (POWNERITEM)mp2;
554
555 // _Pmpf(("WM_DRAWITEM poi->idItem %d", poi->idItem));
556
557 // check if we're to draw the icon
558 // (and not the text)
559 if (poi->idItem == CMA_ICON)
560 {
561 PCNRDRAWITEMINFO pcdi = (PCNRDRAWITEMINFO)poi->hItem;
562 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pcdi->pRecord;
563
564 if (precc->ulStyle & WS_VISIBLE)
565 {
566 USHORT usRow,
567 usColumn;
568
569 switch (precc->usCheckState)
570 {
571 case 0: // unchecked
572 usRow = 2;
573 usColumn = 0;
574 break;
575
576 case 1: // checked
577 usRow = 2;
578 usColumn = 1;
579 break;
580
581 case 2: // indeterminate
582 usRow = 0;
583 usColumn = 1;
584 break;
585 }
586
587 if (precc->ulStyle & BS_BITMAP)
588 // button currently depressed:
589 // add two to column
590 usColumn += 2;
591
592 ctlDrawCheckbox(poi->hps,
593 poi->rclItem.xLeft,
594 poi->rclItem.yBottom,
595 usRow,
596 usColumn,
597 // halftoned?
598 ((precc->recc.flRecordAttr & CRA_DISABLED) != 0));
599 mrc = (MPARAM)FALSE;
600 // we still need the cnr to draw the
601 // emphasis
602 }
603 else
604 mrc = (MPARAM)TRUE; // tell cnr that we've drawn the item;
605 // don't even draw emphasis
606 }
607 else if (poi->idItem == CMA_TEXT)
608 {
609 // for text, buttons etc.:
610 PCNRDRAWITEMINFO pcdi = (PCNRDRAWITEMINFO)poi->hItem;
611 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)pcdi->pRecord;
612 if (precc->recc.flRecordAttr & CRA_DISABLED)
613 {
614 RECTL rcl2;
615 LONG lBackground, lForeground;
616 ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT;
617 if ((pcdi->pRecord->flRecordAttr) & CRA_SELECTED)
618 {
619 // disabled and selected:
620 lBackground = WinQuerySysColor(HWND_DESKTOP,
621 SYSCLR_SHADOWTEXT, 0);
622 lForeground = winhQueryPresColor(poi->hwnd,
623 PP_BACKGROUNDCOLOR,
624 FALSE, // no inherit
625 SYSCLR_WINDOW);
626 }
627 else
628 {
629 // disabled and not selected:
630 lBackground = winhQueryPresColor(poi->hwnd,
631 PP_BACKGROUNDCOLOR,
632 FALSE,
633 SYSCLR_WINDOW);
634 lForeground = winhQueryPresColor(poi->hwnd,
635 PP_FOREGROUNDCOLOR,
636 FALSE, // no inherit
637 SYSCLR_WINDOWTEXT);
638 flCmd |= DT_HALFTONE;
639 }
640
641 // _Pmpf(("back: 0x%lX, fore: 0x%lX", lBackground, lForeground));
642
643 GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL);
644 GpiSetBackColor(poi->hps, lBackground);
645 GpiSetColor(poi->hps, lForeground);
646
647 memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2));
648
649 winhDrawFormattedText(poi->hps,
650 &rcl2,
651 precc->recc.pszTree,
652 flCmd);
653 mrc = (MPARAM)TRUE;
654 }
655 else
656 // tell cnr to draw the item
657 mrc = (MPARAM)FALSE;
658 }
659 else
660 // tell cnr to draw the item
661 mrc = (MPARAM)FALSE;
662 }
663 else
664 mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2);
665 break; }
666
667 default:
668 mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2);
669 }
670 }
671 else
672 mrc = WinDefWindowProc(hwndOwner, msg, mp1, mp2);
673
674 return (mrc);
675}
676
677/*
678 *@@ ctlMakeCheckboxContainer:
679 * this turns a regular container into a "checkbox"
680 * container. This means that the container record
681 * icons are painted as checkboxes, whose status
682 * is determined using an extended record core
683 * structure (CHECKBOXRECORDCORE).
684 *
685 * This function assumes that all records in the
686 * container use this special extended record core
687 * ONLY. You cannot use regular RECORDCORE's when
688 * using this function. Of course, you can extend
689 * the CHECKBOXRECORDCORE structure to the bottom
690 * if you need more fields.
691 *
692 * This subclasses BOTH the container and the container
693 * owner to intercept a number of messages and to
694 * implement owner draw. This is totally transparent
695 * to the caller; QWL_USER is not used for this, so
696 * you can still store your own stuff in there.
697 *
698 * Returns FALSE upon errors.
699 *
700 * To set up a checkbox container, call this function
701 * (which switches the container to Tree view automatically).
702 * Then, allocate and insert CHECKBOXRECORDCORE's as usual.
703 *
704 * To set and query a record's check state easily, use
705 * ctlSetRecordChecked and ctlQueryRecordChecked.
706 *
707 * The checkboxes work almost identically to regular
708 * checkboxes. The user can interact with the checkbox
709 * by clicking on the checkbox itself or by double-clicking
710 * on the record text or by pressing the Enter or Space keys.
711 *
712 * Set CHECKBOXRECORDCORE.ulStyle to one of the regular
713 * checkbox button style bits; if one of the "auto" flags
714 * is set, the checkbox is toggled automatically.
715 *
716 * Even if "auto" is off, when the user changes the check
717 * box selection, hwndCnrOwner gets sent a WM_CONTROL message
718 * with the following parameters:
719 *
720 * -- mp1: USHORT id: usCnrID, as passed to this func
721 * -- mp1: USHORT usNotifyCode: CN_RECORDCHECKED (999)
722 * -- mp2: PCHECKRECORDCORE precc: the record which was (un)checked.
723 *
724 * Note that the subclassed container owner proc filters out
725 * CN_ENTER, so you'll never receive that (but CN_RECORDCHECKED
726 * instead).
727 *
728 * If the "auto" style bits have not been set, you must call
729 * ctlSetRecordChecked yourself then.
730 *
731 *@@added V0.9.0 (99-11-28) [umoeller]
732 */
733
734BOOL ctlMakeCheckboxContainer(HWND hwndCnrOwner, // in: owner (and parent) of container
735 USHORT usCnrID) // in: ID of container in hwndCnrOwner
736{
737 BOOL brc = FALSE;
738
739 HWND hwndCnr = WinWindowFromID(hwndCnrOwner, usCnrID);
740
741 // create mutex-protected list of container owners
742 if (G_hmtxCnrOwnersList == 0)
743 if (DosCreateMutexSem(NULL,
744 &G_hmtxCnrOwnersList, 0, FALSE) != NO_ERROR)
745 return (FALSE);
746
747 if (G_pllCnrOwners == NULL)
748 G_pllCnrOwners = lstCreate(TRUE);
749
750 if (hwndCnr)
751 {
752 if (G_hbmCheckboxes == NULLHANDLE)
753 {
754 // first call:
755 BITMAPINFOHEADER bmih;
756 // load checkboxes bitmap
757 G_hbmCheckboxes = WinGetSysBitmap(HWND_DESKTOP,
758 SBMP_CHECKBOXES);
759
760 // _Pmpf(("hbmCheckboxes: 0x%lX", G_hbmCheckboxes));
761
762 // and compute size of one checkbox
763 // (4 columns, 3 rows)
764 GpiQueryBitmapParameters(G_hbmCheckboxes,
765 &bmih);
766 G_cxCheckbox = bmih.cx / 4;
767 }
768
769 BEGIN_CNRINFO()
770 {
771 cnrhSetView(CV_TREE | CV_ICON | CA_TREELINE | CA_OWNERDRAW | CV_MINI);
772 cnrhSetTreeIndent(20);
773 cnrhSetBmpOrIconSize(G_cxCheckbox, G_cxCheckbox);
774 // cnrhSetSortFunc(fnCompareName);
775 } END_CNRINFO(hwndCnr);
776
777 if ( (hwndCnrOwner)
778 && (G_hmtxCnrOwnersList)
779 )
780 {
781 // subclass container owner
782 PFNWP pfnwpOwnerOrig = WinSubclassWindow(hwndCnrOwner, ctl_fnwpSubclCheckboxCnrOwner);
783 /* _Pmpf(("Subclassed hwnd 0x%lX: orig 0x%lX",
784 hwndCnrOwner, pfnwpOwnerOrig)); */
785 if (pfnwpOwnerOrig)
786 {
787 // owner successfully subclassed:
788 // subclass container too
789 PFNWP pfnwpCnrOrig = WinSubclassWindow(hwndCnr, ctl_fnwpSubclCheckboxCnr);
790 if (pfnwpCnrOrig)
791 {
792 // cnr successfully subclassed:
793 // create storage for both subclassed cnr and owner
794 PCHECKBOXCNROWNER pcbco = (PCHECKBOXCNROWNER)malloc(sizeof(CHECKBOXCNROWNER));
795 if (pcbco)
796 {
797 memset(pcbco, 0, sizeof(CHECKBOXCNROWNER));
798 pcbco->hwndCnr = hwndCnr;
799 pcbco->usCnrID = usCnrID;
800 pcbco->hwndOwner = hwndCnrOwner;
801 pcbco->pfnwpCnrOrig = pfnwpCnrOrig;
802 pcbco->pfnwpOwnerOrig = pfnwpOwnerOrig;
803
804 pcbco->habCnr = WinQueryAnchorBlock(hwndCnr);
805
806 if (WinRequestMutexSem(G_hmtxCnrOwnersList, 5000) == NO_ERROR)
807 {
808 lstAppendItem(G_pllCnrOwners, pcbco);
809 DosReleaseMutexSem(G_hmtxCnrOwnersList);
810 brc = TRUE;
811 }
812 }
813
814 if (!brc)
815 // failed: unsubclass cnr
816 WinSubclassWindow(hwndCnr, pfnwpCnrOrig);
817 }
818
819 if (!brc)
820 // failed: unsubclass owner
821 WinSubclassWindow(hwndCnrOwner, pfnwpOwnerOrig);
822 }
823 }
824 }
825
826 return (brc);
827}
828
829/*
830 *@@ fncbFindCheckRecord:
831 * helper callback for finding a checkbox
832 * record according to an item ID. Used
833 * with cnrhForAllRecords.
834 *
835 * Returns 1 if found to make
836 * cnrhForAllRecords stop searching.
837 *
838 *@@added V0.9.0 (99-11-28) [umoeller]
839 */
840
841ULONG EXPENTRY fncbFindCheckRecord(HWND hwndCnr, // in: container
842 PRECORDCORE preccThis, // in: current record (from cnrhForAllRecords)
843 ULONG ulItemID, // in: item ID to find
844 ULONG ulppRecc) // out: PRECORDCORE* if found
845{
846 ULONG ulrc = 0;
847 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)preccThis;
848 if (precc)
849 {
850 if (precc->ulItemID == ulItemID)
851 {
852 // found:
853 PCHECKBOXRECORDCORE *pprecc = (PCHECKBOXRECORDCORE*)ulppRecc;
854 // store
855 *pprecc = precc;
856 // and stop
857 ulrc = 1;
858 }
859 }
860 return (ulrc);
861}
862
863/*
864 *@@ ctlFindCheckRecord:
865 * this searches the given checkbox container
866 * for the record which matches the given item
867 * ID. Returns NULL if not found.
868 *
869 *@@added V0.9.1 (99-12-03) [umoeller]
870 */
871
872PCHECKBOXRECORDCORE ctlFindCheckRecord(HWND hwndCnr,
873 ULONG ulItemID)
874{
875 PCHECKBOXRECORDCORE precc = 0;
876
877 cnrhForAllRecords(hwndCnr,
878 NULL, // start with root
879 fncbFindCheckRecord,
880 (ULONG)ulItemID, // input
881 (ULONG)&precc);
882
883 return (precc);
884}
885
886/*
887 *@@ ctlSetRecordChecked:
888 * this searches the given checkbox container
889 * for the record which matches the given item
890 * ID and updates that record check state.
891 *
892 * The check state may be:
893 * -- 0: not checked (as with regular checkboxes)
894 * -- 1: checked (as with regular checkboxes)
895 * -- 2: indeterminate (as with regular checkboxes)
896 *
897 * Returns FALSE if the record could not be found.
898 *
899 *@@added V0.9.0 (99-11-28) [umoeller]
900 */
901
902BOOL ctlSetRecordChecked(HWND hwndCnr, // in: container prepared with
903 // ctlMakeCheckboxContainer
904 ULONG ulItemID, // in: record item ID
905 USHORT usCheckState) // in: 0, 1, 2, 3
906{
907 BOOL brc = FALSE;
908 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
909
910 if (precc)
911 {
912 precc->usCheckState = usCheckState;
913 WinSendMsg(hwndCnr,
914 CM_INVALIDATERECORD,
915 (MPARAM)&precc,
916 MPFROM2SHORT(1,
917 CMA_NOREPOSITION));
918 brc = TRUE;
919 }
920
921 return (brc);
922}
923
924/*
925 *@@ ctlQueryRecordChecked:
926 * this searches the given checkbox container
927 * for the record which matches the given item
928 * ID and returns that record's check state.
929 *
930 * Returns:
931 * -- 0: not checked (as with regular checkboxes)
932 * -- 1: checked (as with regular checkboxes)
933 * -- 2: indeterminate (as with regular checkboxes)
934 * -- -1: record not found.
935 *
936 *@@added V0.9.0 (99-11-28) [umoeller]
937 */
938
939ULONG ctlQueryRecordChecked(HWND hwndCnr, // in: container prepared with
940 // ctlMakeCheckboxContainer
941 ULONG ulItemID, // in: record item ID
942 USHORT usCheckState) // in: 0, 1, 2, 3
943{
944 ULONG ulrc = -1;
945 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
946
947 if (precc)
948 ulrc = precc->usCheckState;
949
950 return (ulrc);
951}
952
953/*
954 *@@ ctlEnableRecord:
955 * this searches the given checkbox container
956 * for the record which matches the given item
957 * ID and updates that record enablement. If
958 * the record is disabled, it's painted halftoned
959 * by ctl_fnwpSubclCheckboxCnr.
960 *
961 *@@added V0.9.1 (99-12-03) [umoeller]
962 */
963
964BOOL ctlEnableRecord(HWND hwndCnr,
965 ULONG ulItemID,
966 BOOL fEnable)
967{
968 BOOL brc = FALSE;
969 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
970
971 if (precc)
972 {
973 ULONG ulAttr = precc->recc.flRecordAttr;
974 if (fEnable)
975 precc->recc.flRecordAttr &= ~CRA_DISABLED;
976 else
977 precc->recc.flRecordAttr |= CRA_DISABLED;
978
979 if (precc->recc.flRecordAttr != ulAttr)
980 // attrs changed: repaint
981 WinSendMsg(hwndCnr,
982 CM_INVALIDATERECORD,
983 (MPARAM)&precc,
984 MPFROM2SHORT(1,
985 CMA_NOREPOSITION));
986
987 brc = TRUE;
988 }
989
990 return (brc);
991}
992
993
Note: See TracBrowser for help on using the repository browser.