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

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

Misc updates

  • 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 }
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
648 winhDrawFormattedText(poi->hps,
649 &rcl2,
650 precc->recc.pszTree,
651 flCmd);
652 mrc = (MPARAM)TRUE;
653 }
654 else
655 // tell cnr to draw the item
656 mrc = (MPARAM)FALSE;
657 }
658 else
659 // tell cnr to draw the item
660 mrc = (MPARAM)FALSE;
661 }
662 else
663 mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2);
664 break; }
665
666 default:
667 mrc = pfnwpOrig(hwndOwner, msg, mp1, mp2);
668 }
669 }
670 else
671 mrc = WinDefWindowProc(hwndOwner, msg, mp1, mp2);
672
673 return (mrc);
674}
675
676/*
677 *@@ ctlMakeCheckboxContainer:
678 * this turns a regular container into a "checkbox"
679 * container. This means that the container record
680 * icons are painted as checkboxes, whose status
681 * is determined using an extended record core
682 * structure (CHECKBOXRECORDCORE).
683 *
684 * This function assumes that all records in the
685 * container use this special extended record core
686 * ONLY. You cannot use regular RECORDCORE's when
687 * using this function. Of course, you can extend
688 * the CHECKBOXRECORDCORE structure to the bottom
689 * if you need more fields.
690 *
691 * This subclasses BOTH the container and the container
692 * owner to intercept a number of messages and to
693 * implement owner draw. This is totally transparent
694 * to the caller; QWL_USER is not used for this, so
695 * you can still store your own stuff in there.
696 *
697 * Returns FALSE upon errors.
698 *
699 * To set up a checkbox container, call this function
700 * (which switches the container to Tree view automatically).
701 * Then, allocate and insert CHECKBOXRECORDCORE's as usual.
702 *
703 * To set and query a record's check state easily, use
704 * ctlSetRecordChecked and ctlQueryRecordChecked.
705 *
706 * The checkboxes work almost identically to regular
707 * checkboxes. The user can interact with the checkbox
708 * by clicking on the checkbox itself or by double-clicking
709 * on the record text or by pressing the Enter or Space keys.
710 *
711 * Set CHECKBOXRECORDCORE.ulStyle to one of the regular
712 * checkbox button style bits; if one of the "auto" flags
713 * is set, the checkbox is toggled automatically.
714 *
715 * Even if "auto" is off, when the user changes the check
716 * box selection, hwndCnrOwner gets sent a WM_CONTROL message
717 * with the following parameters:
718 *
719 * -- mp1: USHORT id: usCnrID, as passed to this func
720 * -- mp1: USHORT usNotifyCode: CN_RECORDCHECKED (999)
721 * -- mp2: PCHECKRECORDCORE precc: the record which was (un)checked.
722 *
723 * Note that the subclassed container owner proc filters out
724 * CN_ENTER, so you'll never receive that (but CN_RECORDCHECKED
725 * instead).
726 *
727 * If the "auto" style bits have not been set, you must call
728 * ctlSetRecordChecked yourself then.
729 *
730 *@@added V0.9.0 (99-11-28) [umoeller]
731 */
732
733BOOL ctlMakeCheckboxContainer(HWND hwndCnrOwner, // in: owner (and parent) of container
734 USHORT usCnrID) // in: ID of container in hwndCnrOwner
735{
736 BOOL brc = FALSE;
737
738 HWND hwndCnr = WinWindowFromID(hwndCnrOwner, usCnrID);
739
740 // create mutex-protected list of container owners
741 if (G_hmtxCnrOwnersList == 0)
742 if (DosCreateMutexSem(NULL,
743 &G_hmtxCnrOwnersList, 0, FALSE) != NO_ERROR)
744 return (FALSE);
745
746 if (G_pllCnrOwners == NULL)
747 G_pllCnrOwners = lstCreate(TRUE);
748
749 if (hwndCnr)
750 {
751 if (G_hbmCheckboxes == NULLHANDLE)
752 {
753 // first call:
754 BITMAPINFOHEADER bmih;
755 // load checkboxes bitmap
756 G_hbmCheckboxes = WinGetSysBitmap(HWND_DESKTOP,
757 SBMP_CHECKBOXES);
758
759 // _Pmpf(("hbmCheckboxes: 0x%lX", G_hbmCheckboxes));
760
761 // and compute size of one checkbox
762 // (4 columns, 3 rows)
763 GpiQueryBitmapParameters(G_hbmCheckboxes,
764 &bmih);
765 G_cxCheckbox = bmih.cx / 4;
766 }
767
768 BEGIN_CNRINFO()
769 {
770 cnrhSetView(CV_TREE | CV_ICON | CA_TREELINE | CA_OWNERDRAW | CV_MINI);
771 cnrhSetTreeIndent(20);
772 cnrhSetBmpOrIconSize(G_cxCheckbox, G_cxCheckbox);
773 // cnrhSetSortFunc(fnCompareName);
774 } END_CNRINFO(hwndCnr);
775
776 if ( (hwndCnrOwner)
777 && (G_hmtxCnrOwnersList)
778 )
779 {
780 // subclass container owner
781 PFNWP pfnwpOwnerOrig = WinSubclassWindow(hwndCnrOwner, ctl_fnwpSubclCheckboxCnrOwner);
782 /* _Pmpf(("Subclassed hwnd 0x%lX: orig 0x%lX",
783 hwndCnrOwner, pfnwpOwnerOrig)); */
784 if (pfnwpOwnerOrig)
785 {
786 // owner successfully subclassed:
787 // subclass container too
788 PFNWP pfnwpCnrOrig = WinSubclassWindow(hwndCnr, ctl_fnwpSubclCheckboxCnr);
789 if (pfnwpCnrOrig)
790 {
791 // cnr successfully subclassed:
792 // create storage for both subclassed cnr and owner
793 PCHECKBOXCNROWNER pcbco = (PCHECKBOXCNROWNER)malloc(sizeof(CHECKBOXCNROWNER));
794 if (pcbco)
795 {
796 memset(pcbco, 0, sizeof(CHECKBOXCNROWNER));
797 pcbco->hwndCnr = hwndCnr;
798 pcbco->usCnrID = usCnrID;
799 pcbco->hwndOwner = hwndCnrOwner;
800 pcbco->pfnwpCnrOrig = pfnwpCnrOrig;
801 pcbco->pfnwpOwnerOrig = pfnwpOwnerOrig;
802
803 pcbco->habCnr = WinQueryAnchorBlock(hwndCnr);
804
805 if (WinRequestMutexSem(G_hmtxCnrOwnersList, 5000) == NO_ERROR)
806 {
807 lstAppendItem(G_pllCnrOwners, pcbco);
808 DosReleaseMutexSem(G_hmtxCnrOwnersList);
809 brc = TRUE;
810 }
811 }
812
813 if (!brc)
814 // failed: unsubclass cnr
815 WinSubclassWindow(hwndCnr, pfnwpCnrOrig);
816 }
817
818 if (!brc)
819 // failed: unsubclass owner
820 WinSubclassWindow(hwndCnrOwner, pfnwpOwnerOrig);
821 }
822 }
823 }
824
825 return (brc);
826}
827
828/*
829 *@@ fncbFindCheckRecord:
830 * helper callback for finding a checkbox
831 * record according to an item ID. Used
832 * with cnrhForAllRecords.
833 *
834 * Returns 1 if found to make
835 * cnrhForAllRecords stop searching.
836 *
837 *@@added V0.9.0 (99-11-28) [umoeller]
838 */
839
840ULONG EXPENTRY fncbFindCheckRecord(HWND hwndCnr, // in: container
841 PRECORDCORE preccThis, // in: current record (from cnrhForAllRecords)
842 ULONG ulItemID, // in: item ID to find
843 ULONG ulppRecc) // out: PRECORDCORE* if found
844{
845 ULONG ulrc = 0;
846 PCHECKBOXRECORDCORE precc = (PCHECKBOXRECORDCORE)preccThis;
847 if (precc)
848 {
849 if (precc->ulItemID == ulItemID)
850 {
851 // found:
852 PCHECKBOXRECORDCORE *pprecc = (PCHECKBOXRECORDCORE*)ulppRecc;
853 // store
854 *pprecc = precc;
855 // and stop
856 ulrc = 1;
857 }
858 }
859 return (ulrc);
860}
861
862/*
863 *@@ ctlFindCheckRecord:
864 * this searches the given checkbox container
865 * for the record which matches the given item
866 * ID. Returns NULL if not found.
867 *
868 *@@added V0.9.1 (99-12-03) [umoeller]
869 */
870
871PCHECKBOXRECORDCORE ctlFindCheckRecord(HWND hwndCnr,
872 ULONG ulItemID)
873{
874 PCHECKBOXRECORDCORE precc = 0;
875
876 cnrhForAllRecords(hwndCnr,
877 NULL, // start with root
878 fncbFindCheckRecord,
879 (ULONG)ulItemID, // input
880 (ULONG)&precc);
881
882 return (precc);
883}
884
885/*
886 *@@ ctlSetRecordChecked:
887 * this searches the given checkbox container
888 * for the record which matches the given item
889 * ID and updates that record check state.
890 *
891 * The check state may be:
892 * -- 0: not checked (as with regular checkboxes)
893 * -- 1: checked (as with regular checkboxes)
894 * -- 2: indeterminate (as with regular checkboxes)
895 *
896 * Returns FALSE if the record could not be found.
897 *
898 *@@added V0.9.0 (99-11-28) [umoeller]
899 */
900
901BOOL ctlSetRecordChecked(HWND hwndCnr, // in: container prepared with
902 // ctlMakeCheckboxContainer
903 ULONG ulItemID, // in: record item ID
904 USHORT usCheckState) // in: 0, 1, 2, 3
905{
906 BOOL brc = FALSE;
907 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
908
909 if (precc)
910 {
911 precc->usCheckState = usCheckState;
912 WinSendMsg(hwndCnr,
913 CM_INVALIDATERECORD,
914 (MPARAM)&precc,
915 MPFROM2SHORT(1,
916 CMA_NOREPOSITION));
917 brc = TRUE;
918 }
919
920 return (brc);
921}
922
923/*
924 *@@ ctlQueryRecordChecked:
925 * this searches the given checkbox container
926 * for the record which matches the given item
927 * ID and returns that record's check state.
928 *
929 * Returns:
930 * -- 0: not checked (as with regular checkboxes)
931 * -- 1: checked (as with regular checkboxes)
932 * -- 2: indeterminate (as with regular checkboxes)
933 * -- -1: record not found.
934 *
935 *@@added V0.9.0 (99-11-28) [umoeller]
936 */
937
938ULONG ctlQueryRecordChecked(HWND hwndCnr, // in: container prepared with
939 // ctlMakeCheckboxContainer
940 ULONG ulItemID, // in: record item ID
941 USHORT usCheckState) // in: 0, 1, 2, 3
942{
943 ULONG ulrc = -1;
944 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
945
946 if (precc)
947 ulrc = precc->usCheckState;
948
949 return (ulrc);
950}
951
952/*
953 *@@ ctlEnableRecord:
954 * this searches the given checkbox container
955 * for the record which matches the given item
956 * ID and updates that record enablement. If
957 * the record is disabled, it's painted halftoned
958 * by ctl_fnwpSubclCheckboxCnr.
959 *
960 *@@added V0.9.1 (99-12-03) [umoeller]
961 */
962
963BOOL ctlEnableRecord(HWND hwndCnr,
964 ULONG ulItemID,
965 BOOL fEnable)
966{
967 BOOL brc = FALSE;
968 PCHECKBOXRECORDCORE precc = ctlFindCheckRecord(hwndCnr, ulItemID);
969
970 if (precc)
971 {
972 ULONG ulAttr = precc->recc.flRecordAttr;
973 if (fEnable)
974 precc->recc.flRecordAttr &= ~CRA_DISABLED;
975 else
976 precc->recc.flRecordAttr |= CRA_DISABLED;
977
978 if (precc->recc.flRecordAttr != ulAttr)
979 // attrs changed: repaint
980 WinSendMsg(hwndCnr,
981 CM_INVALIDATERECORD,
982 (MPARAM)&precc,
983 MPFROM2SHORT(1,
984 CMA_NOREPOSITION));
985
986 brc = TRUE;
987 }
988
989 return (brc);
990}
991
992
Note: See TracBrowser for help on using the repository browser.