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

Last change on this file since 190 was 184, checked in by umoeller, 23 years ago

Second round of fixes for 0.9.19.

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