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

Last change on this file since 19 was 14, checked in by umoeller, 25 years ago

Major updates; timers, LVM, miscellaneous.

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