source: trunk/src/helpers/cctl_cnr.c@ 242

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

First attempt at new container contol.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 45.2 KB
Line 
1
2/*
3 *@@sourcefile cctl_cnr.c:
4 * implementation for the replacement container control.
5 *
6 *@@header "helpers\comctl.h"
7 *@@added V1.0.1 (2003-01-17) [umoeller]
8 */
9
10/*
11 * Copyright (C) 2003 Ulrich M”ller.
12 * This file is part of the "XWorkplace helpers" source package.
13 * This is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published
15 * by the Free Software Foundation, in version 2 as it comes in the
16 * "COPYING" file of the XWorkplace main distribution.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
22
23#define OS2EMX_PLAIN_CHAR
24 // this is needed for "os2emx.h"; if this is defined,
25 // emx will define PSZ as _signed_ char, otherwise
26 // as unsigned char
27
28#define INCL_WINWINDOWMGR
29#define INCL_WINFRAMEMGR
30#define INCL_WINSYS
31#define INCL_WINSCROLLBARS
32#define INCL_WINSTDCNR
33
34#define INCL_GPIPRIMITIVES
35#define INCL_GPILCIDS
36#include <os2.h>
37
38#include "setup.h" // code generation and debugging options
39
40#include "helpers\comctl.h"
41#include "helpers\linklist.h"
42#include "helpers\gpih.h"
43#include "helpers\nls.h"
44#include "helpers\standards.h"
45#include "helpers\stringh.h"
46#include "helpers\tree.h"
47#include "helpers\winh.h"
48
49#include "private\cnr.h"
50
51#pragma hdrstop
52
53/*
54 *@@category: Helpers\PM helpers\Window classes\Container control replacement
55 * See cctl_cnr.c.
56 */
57
58/* ******************************************************************
59 *
60 * Global variables
61 *
62 ********************************************************************/
63
64extern const SYSCOLORSET G_scsCnr =
65 {
66 TRUE, // inherit presparams
67 SYSCLR_WINDOW,
68 SYSCLR_WINDOWTEXT
69 };
70
71/* ******************************************************************
72 *
73 * Helper funcs
74 *
75 ********************************************************************/
76
77VOID cnrDrawString(HPS hps,
78 PCSZ pcsz, // in: string to test
79 PRECTL prcl, // in: clipping rectangle (inclusive!)
80 ULONG fl, // in: alignment flags
81 PFONTMETRICS pfm)
82{
83 ULONG fl2 = 0;
84/*
85 #define CFA_LEFT 0x00000001L
86 #define CFA_RIGHT 0x00000002L
87 #define CFA_CENTER 0x00000004L
88 #define CFA_TOP 0x00000008L
89 #define CFA_VCENTER 0x00000010L
90 #define CFA_BOTTOM 0x00000020L
91
92 * -- DT_LEFT 0x00000000
93 * -- DT_CENTER 0x00000100
94 * -- DT_RIGHT 0x00000200
95 * -- DT_TOP 0x00000000
96 * -- DT_VCENTER 0x00000400
97 * -- DT_BOTTOM 0x00000800
98*/
99 if (fl & CFA_RIGHT)
100 fl2 = DT_RIGHT;
101 else if (fl & CFA_CENTER)
102 fl2 = DT_CENTER;
103
104 if (fl & CFA_BOTTOM)
105 fl2 = DT_BOTTOM;
106 else if (fl & CFA_VCENTER)
107 fl2 = DT_VCENTER;
108
109 gpihDrawString(hps,
110 pcsz,
111 prcl,
112 fl2,
113 pfm);
114}
115
116/*
117 *@@ CreateChild:
118 * creates a container child window.
119 */
120
121HWND CreateChild(PCNRDATA pData,
122 PCSZ pcszClass,
123 ULONG id)
124{
125 return WinCreateWindow(pData->dwdMain.hwnd,
126 (PSZ)pcszClass,
127 NULL,
128 WS_VISIBLE,
129 0,
130 0,
131 0,
132 0,
133 pData->dwdMain.hwnd,
134 HWND_TOP,
135 id,
136 pData,
137 NULL);
138}
139
140/*
141 *@@ FindColumnFromFI:
142 *
143 */
144
145PDETAILCOLUMN FindColumnFromFI(PCNRDATA pData,
146 const FIELDINFO *pfi,
147 PLISTNODE *ppNode) // out: listnode of column
148{
149 PLISTNODE pNode;
150 FOR_ALL_NODES(&pData->llColumns, pNode)
151 {
152 PDETAILCOLUMN pCol = pNode->pItemData;
153 if (pCol->pfi == pfi)
154 {
155 if (ppNode)
156 *ppNode = pNode;
157
158 return pCol;
159 }
160 }
161
162 return NULL;
163}
164
165/*
166 *@@ FindListNodeForRecc:
167 *
168 */
169
170PLISTNODE FindListNodeForRecc(PCNRDATA pData,
171 const RECORDCORE *precc)
172{
173 RECORDTREEITEM *pti;
174 if (pti = (PRECORDTREEITEM)treeFind(pData->RecordsTree,
175 (ULONG)precc,
176 treeCompareKeys))
177 return pti->pListNode;
178
179 return NULL;
180}
181
182/* ******************************************************************
183 *
184 * Standard window messages
185 *
186 ********************************************************************/
187
188/*
189 *@@ CnrCreate:
190 * implementation for WM_CREATE in fnwpCnr.
191 */
192
193MRESULT CnrCreate(HWND hwnd, MPARAM mp1, MPARAM mp2)
194{
195 PCNRDATA pData;
196
197 if (!(pData = NEW(CNRDATA)))
198 return (MRESULT)TRUE; // stop window creation
199
200 WinSetWindowPtr(hwnd, QWL_USER + 1, pData);
201 ZERO(pData);
202
203 // initialize DEFWINDOWDATA
204 ctlInitDWD(hwnd,
205 mp2,
206 &pData->dwdMain,
207 WinDefWindowProc,
208 &G_scsCnr);
209
210 if (winhQueryWindowStyle(hwnd) & CCS_MINIRECORDCORE)
211 pData->fMiniRecords = TRUE;
212
213 // set up non-zero default values in cnrinfo
214 pData->CnrInfo.cb = sizeof(CNRINFO);
215 pData->CnrInfo.xVertSplitbar = -1;
216
217 lstInit(&pData->llAllocatedFIs,
218 TRUE);
219 lstInit(&pData->llColumns,
220 TRUE);
221 lstInit(&pData->llAllocatedRecs,
222 TRUE);
223 lstInit(&pData->llRootRecords,
224 TRUE);
225
226 treeInit(&pData->RecordsTree,
227 (PLONG)&pData->CnrInfo.cRecords);
228
229 nlsQueryCountrySettings(&pData->cs);
230
231 winhCreateScrollBars(hwnd,
232 &pData->hwndVScroll,
233 &pData->hwndHScroll);
234
235 pData->cxScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
236 pData->cyScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
237
238 return (MRESULT)FALSE;
239}
240
241/*
242 *@@ CnrSem2:
243 * implementation for WM_SEM2 in fnwpCnr.
244 *
245 * The DDFL_* semaphore bits get set whenever the
246 * view needs to recompute something. In the worst
247 * case, we resize and/or invalidate the window.
248 */
249
250VOID CnrSem2(HWND hwnd, ULONG fl)
251{
252 PCNRDATA pData;
253 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
254 {
255 if (pData->CnrInfo.flWindowAttr & CV_DETAIL)
256 {
257 if (fl & (DDFL_INVALIDATECOLUMNS | DDFL_INCALIDATERECORDS))
258 {
259 HPS hps = WinGetPS(hwnd);
260 cdtlRecalcDetails(pData, hps, &fl);
261 WinReleasePS(hps);
262
263 if (fl & DDFL_WINDOWSIZECHANGED)
264 WinInvalidateRect(pData->dwdMain.hwnd, NULL, TRUE);
265 }
266
267 if (fl & (DDFL_WINDOWSIZECHANGED | DDFL_WORKAREACHANGED))
268 {
269 LONG y = 0,
270 cx = pData->dwdMain.szlWin.cx,
271 cy = pData->dwdMain.szlWin.cy - pData->cyColTitlesBox;
272
273 if (pData->hwndVScroll)
274 cx -= pData->cxScrollBar;
275 if (pData->hwndHScroll)
276 {
277 y += pData->cyScrollBar;
278 cy -= pData->cyScrollBar;
279 }
280
281 _PmpfF(("cyColTitlesBox %d, new cy: %d", pData->cyColTitlesBox, cy));
282
283 if (fl & DDFL_WINDOWSIZECHANGED)
284 WinSetWindowPos(pData->hwndDetails,
285 HWND_TOP,
286 0,
287 y,
288 cx,
289 cy,
290 SWP_MOVE | SWP_SIZE);
291 // SWP_MOVE is required or PM will move our
292 // subwindow to some adjustment position
293
294 if (pData->hwndVScroll)
295 {
296 WinSetWindowPos(pData->hwndVScroll,
297 HWND_TOP,
298 cx,
299 y,
300 pData->cxScrollBar,
301 cy,
302 SWP_MOVE | SWP_SIZE);
303
304 _PmpfF(("updating VScroll, cy: %d, szlWorkarea.cy: %d",
305 cy,
306 pData->szlWorkarea.cy));
307
308 winhUpdateScrollBar(pData->hwndVScroll,
309 cy,
310 pData->szlWorkarea.cy,
311 pData->ptlScrollOfs.y,
312 FALSE);
313 }
314
315 if (pData->hwndHScroll)
316 {
317 WinSetWindowPos(pData->hwndHScroll,
318 HWND_TOP,
319 0,
320 0,
321 cx,
322 pData->cyScrollBar,
323 SWP_MOVE | SWP_SIZE);
324
325 _PmpfF(("updating HScroll, cx: %d, szlWorkarea.cx: %d",
326 cx,
327 pData->szlWorkarea.cx));
328
329 winhUpdateScrollBar(pData->hwndHScroll,
330 cx,
331 pData->szlWorkarea.cx,
332 pData->ptlScrollOfs.x,
333 FALSE);
334 }
335 }
336 }
337 }
338}
339
340/*
341 *@@ CnrPaint:
342 * implementation for WM_PAINT in fnwpCnr.
343 */
344
345VOID CnrPaint(HWND hwnd)
346{
347 HPS hps;
348 PCNRDATA pData;
349 RECTL rclPaint;
350
351 if ( (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
352 && (hps = WinBeginPaint(hwnd, NULLHANDLE, &rclPaint))
353 )
354 {
355 gpihSwitchToRGB(hps);
356
357 if ( (pData->CnrInfo.flWindowAttr & (CV_DETAIL | CA_DETAILSVIEWTITLES))
358 == (CV_DETAIL | CA_DETAILSVIEWTITLES)
359 )
360 {
361 PLISTNODE pColNode;
362
363 POINTL ptl;
364 RECTL rcl;
365 LONG yPadding = pData->CnrInfo.cyLineSpacing / 2;
366
367 // lowest y that we are allowed to paint at
368 LONG yLowest = pData->dwdMain.szlWin.cy - pData->cyColTitlesBox;
369
370 if (rclPaint.yTop > yLowest)
371 {
372 // clip paint rect so we don't paint into details wnd
373 if (rclPaint.yBottom < yLowest)
374 rclPaint.yBottom = yLowest;
375
376 WinFillRect(hps,
377 &rclPaint,
378 pData->dwdMain.lcolBackground);
379
380 FOR_ALL_NODES(&pData->llColumns, pColNode)
381 {
382 RECTL rcl2;
383 PDETAILCOLUMN pCol = (PDETAILCOLUMN)pColNode->pItemData;
384 const FIELDINFO *pfi = pCol->pfi;
385 PLISTNODE pRecNode;
386 ULONG cRow;
387
388 rcl.xLeft = pCol->xLeft + COLUMN_PADDING_X - pData->ptlScrollOfs.x;
389 rcl.xRight = rcl.xLeft + pCol->cxTotal;
390
391 // we start out at the top and work our way down,
392 // decrementing rcl.yTop with every item we painted
393 rcl.yTop = pData->dwdMain.szlWin.cy;
394
395 rcl.yTop -= COLUMN_PADDING_Y + yPadding;
396 rcl.yBottom = rcl.yTop
397 - pData->cyColTitlesContent;
398
399 if (pfi->flTitle & CFA_BITMAPORICON)
400 // @@todo
401 ;
402 else
403 {
404 cnrDrawString(hps,
405 (PCSZ)pfi->pTitleData,
406 &rcl,
407 pfi->flTitle,
408 &pData->fm);
409 }
410
411 rcl.yBottom -= COLUMN_PADDING_Y + yPadding;
412
413 if (pfi->flData & CFA_HORZSEPARATOR)
414 {
415 ptl.x = rcl.xLeft;
416 ptl.y = rcl.yBottom;
417
418 GpiMove(hps,
419 &ptl);
420 ptl.x = rcl.xRight;
421 GpiLine(hps,
422 &ptl);
423 }
424
425 rcl.yTop = rcl.yBottom;
426
427 } // FOR_ALL_NODES(&pData->llColumns, pColNode)
428 }
429 }
430
431 WinEndPaint(hps);
432 }
433}
434
435/*
436 *@@ CnrWindowPosChanged:
437 * implementation for WM_WINDOWPOSCHANGED in fnwpCnr.
438 */
439
440MRESULT CnrWindowPosChanged(HWND hwnd,
441 MPARAM mp1,
442 MPARAM mp2)
443{
444 MRESULT mrc = 0;
445 PCNRDATA pData;
446 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
447 {
448 mrc = ctlDefWindowProc(&pData->dwdMain, WM_WINDOWPOSCHANGED, mp1, mp2);
449
450 if (((PSWP)mp1)->fl & SWP_SIZE)
451 {
452 WinPostMsg(hwnd,
453 WM_SEM2,
454 (MPARAM)DDFL_WINDOWSIZECHANGED,
455 0);
456 }
457 }
458
459 return mrc;
460}
461
462/*
463 *@@ cnrPresParamChanged:
464 * implementation for WM_PRESPARAMCHANGED for both
465 * fnwpCnr and fnwpCnrDetails.
466 */
467
468VOID cnrPresParamChanged(HWND hwnd,
469 ULONG ulpp)
470{
471 PCNRDATA pData;
472 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
473 {
474 // note, we use the dwdMain buffer here cos
475 // we share presparams with the cnr
476 ctlRefreshColors(&pData->dwdMain);
477
478 switch (ulpp)
479 {
480 case 0: // layout palette thing dropped
481 case PP_FONTNAMESIZE:
482 if (pData->CnrInfo.flWindowAttr & CV_DETAIL)
483 {
484 // if we got this on the details window,
485 // set it on the main cnr as well, and
486 // vice versa
487 PSZ pszFont;
488 if (pszFont = winhQueryWindowFont(hwnd))
489 {
490 HWND hwndOther;
491 DosBeep(1000, 10);
492 if (hwnd == pData->dwdMain.hwnd)
493 hwndOther = pData->dwdContent.hwnd;
494 else
495 hwndOther = pData->dwdMain.hwnd;
496
497 winhSetWindowFont(hwndOther, pszFont);
498 free(pszFont);
499 }
500
501 WinPostMsg(pData->dwdMain.hwnd,
502 WM_SEM2,
503 (MPARAM)(DDFL_INVALIDATECOLUMNS | DDFL_INCALIDATERECORDS),
504 0);
505 }
506 break;
507
508 default:
509 // just repaint everything
510 WinInvalidateRect(pData->dwdMain.hwnd, NULL, TRUE);
511 }
512 }
513}
514
515/*
516 *@@ CnrScroll:
517 * implementation for WM_HSCROLL and WM_VSCROLL in fnwpCnr.
518 */
519
520VOID CnrScroll(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
521{
522 PCNRDATA pData;
523 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
524 {
525 if (pData->CnrInfo.flWindowAttr & CV_DETAIL)
526 {
527 POINTL ptlScroll;
528 if (msg == WM_HSCROLL)
529 {
530 ptlScroll.y = 0;
531 if (ptlScroll.x = winhHandleScrollMsg2(pData->hwndHScroll,
532 &pData->ptlScrollOfs.x,
533 pData->dwdContent.szlWin.cx,
534 pData->szlWorkarea.cx,
535 5,
536 msg,
537 mp2))
538 {
539 if (pData->CnrInfo.flWindowAttr & CA_DETAILSVIEWTITLES)
540 {
541 RECTL rclClip;
542 rclClip.xLeft = 0;
543 rclClip.xRight = pData->dwdMain.szlWin.cx;
544 rclClip.yBottom = pData->dwdMain.szlWin.cy - pData->cyColTitlesBox;
545 rclClip.yTop = pData->dwdMain.szlWin.cy;
546 winhScrollWindow(hwnd,
547 &rclClip,
548 &ptlScroll);
549 }
550 winhScrollWindow(pData->hwndDetails,
551 NULL,
552 &ptlScroll);
553 }
554 }
555 else
556 {
557 ptlScroll.x = 0;
558 if (ptlScroll.y = winhHandleScrollMsg2(pData->hwndVScroll,
559 &pData->ptlScrollOfs.y,
560 pData->dwdContent.szlWin.cy,
561 pData->szlWorkarea.cy,
562 5,
563 msg,
564 mp2))
565 winhScrollWindow(pData->hwndDetails,
566 NULL,
567 &ptlScroll);
568 }
569 }
570 }
571}
572
573/*
574 *@@ CnrDestroy:
575 * implementation for WM_DESTROY in fnwpCnr.
576 */
577
578VOID CnrDestroy(HWND hwnd)
579{
580 PCNRDATA pData;
581 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
582 {
583 // free all data that we ever allocated;
584 // all these lists are auto-free
585 lstClear(&pData->llColumns);
586 lstClear(&pData->llAllocatedFIs);
587 lstClear(&pData->llAllocatedRecs);
588 lstClear(&pData->llRootRecords);
589
590 free(pData);
591 }
592}
593
594/* ******************************************************************
595 *
596 * General container messages
597 *
598 ********************************************************************/
599
600/*
601 *@@ CnrQueryCnrInfo:
602 * implementation for CM_QUERYCNRINFO in fnwpCnr.
603 *
604 * Returns no. of bytes copied.
605 */
606
607USHORT CnrQueryCnrInfo(HWND hwnd,
608 PCNRINFO pci, // in: mp1 of CM_QUERYCNRINFO
609 USHORT cb) // in: mp2 of CM_QUERYCNRINFO
610{
611 PCNRDATA pData;
612 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
613 {
614 USHORT cbCopied = max(cb, sizeof(CNRINFO));
615 memcpy(pci,
616 &pData->CnrInfo,
617 cbCopied);
618 return cbCopied;
619 }
620
621 return 0;
622}
623
624/*
625 *@@ CnrSetCnrInfo:
626 * implementation for CM_SETCNRINFO in fnwpCnr.
627 *
628 * Returns no. of bytes copied.
629 */
630
631BOOL CnrSetCnrInfo(HWND hwnd,
632 PCNRINFO pci, // in: mp1 of CM_SETCNRINFO
633 ULONG flCI) // in: CMA_* flags in mp2 of CM_SETCNRINFO
634{
635 PCNRDATA pData;
636 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
637 {
638 ULONG flDirty = 0;
639
640 if (flCI & CMA_PSORTRECORD)
641 /* Pointer to the comparison function for sorting container records. If NULL,
642 which is the default condition, no sorting is performed. Sorting only occurs
643 during record insertion and when changing the value of this field. The third
644 parameter of the comparison function, pStorage, must be NULL. See
645 CM_SORTRECORD for a further description of the comparison function. */
646 pData->CnrInfo.pSortRecord = pci->pSortRecord;
647
648 if (flCI & CMA_PFIELDINFOLAST)
649 /* Pointer to the last column in the left window of the split details view. The
650 default is NULL, causing all columns to be positioned in the left window. */
651 pData->CnrInfo.pFieldInfoLast = pci->pFieldInfoLast;
652
653 if (flCI & CMA_PFIELDINFOOBJECT)
654 /* Pointer to a column that represents an object in the details view. This
655 FIELDINFO structure must contain icons or bit maps. In-use emphasis is applied
656 to this column of icons or bit maps only. The default is the leftmost column
657 in the unsplit details view, or the leftmost column in the left window of the
658 split details view. */
659 pData->CnrInfo.pFieldInfoObject = pci->pFieldInfoObject;
660
661 if (flCI & CMA_CNRTITLE)
662 {
663 // Text for the container title. The default is NULL.
664 pData->CnrInfo.pszCnrTitle = pci->pszCnrTitle;
665
666 // @@todo recalc window components, repaint
667 }
668
669 if (flCI & CMA_FLWINDOWATTR)
670 {
671 // Container window attributes.
672 if (pData->CnrInfo.flWindowAttr != pci->flWindowAttr)
673 {
674 HWND hwndSwitchOwner = NULLHANDLE;
675
676 pData->CnrInfo.flWindowAttr = pci->flWindowAttr;
677
678 // if switching to details view, then create
679 // details subwindow
680 if (pData->CnrInfo.flWindowAttr & CV_DETAIL)
681 {
682 if (!pData->hwndDetails)
683 {
684 if (pData->hwndDetails = CreateChild(pData,
685 WC_CCTL_CNR_DETAILS,
686 CID_LEFTDVWND))
687 {
688 flDirty = DDFL_ALL;
689 }
690 }
691 }
692 else
693 {
694 winhDestroyWindow(&pData->hwndDetails);
695 }
696 }
697 }
698
699 if (flCI & CMA_PTLORIGIN)
700 {
701 // Lower-left origin of the container window in virtual workspace coordinates,
702 // used in the icon view. The default origin is (0,0).
703 memcpy(&pData->CnrInfo.ptlOrigin,
704 &pci->ptlOrigin,
705 sizeof(POINTL));
706
707 // @@todo recalc window components, repaint
708 }
709
710 if (flCI & CMA_DELTA)
711 {
712 // An application-defined threshold, or number of records, from either end of
713 // the list of available records. Used when a container needs to handle large
714 // amounts of data. The default is 0. Refer to the description of the container
715 // control in the OS/2 Programming Guide for more information about specifying
716 // deltas.
717 pData->CnrInfo.cDelta = pci->cDelta;
718 }
719
720 if (flCI & CMA_SLBITMAPORICON)
721 {
722 // The size (in pels) of icons or bit maps. The default is the system size.
723 memcpy(&pData->CnrInfo.slBitmapOrIcon,
724 &pci->slBitmapOrIcon,
725 sizeof(SIZEL));
726
727 // @@todo recalc window components, repaint
728 }
729
730 if (flCI & CMA_SLTREEBITMAPORICON)
731 {
732 // The size (in pels) of the expanded and collapsed icons or bit maps in the
733 // tree icon and tree text views.
734 memcpy(&pData->CnrInfo.slTreeBitmapOrIcon,
735 &pci->slTreeBitmapOrIcon,
736 sizeof(SIZEL));
737
738 // @@todo recalc window components, repaint
739 }
740
741 if (flCI & CMA_TREEBITMAP)
742 {
743 // Expanded and collapsed bit maps in the tree icon and tree text views.
744 pData->CnrInfo.hbmExpanded = pci->hbmExpanded;
745 pData->CnrInfo.hbmCollapsed = pci->hbmCollapsed;
746
747 // @@todo recalc window components, repaint
748 }
749
750 if (flCI & CMA_TREEICON)
751 {
752 // Expanded and collapsed icons in the tree icon and tree text views.
753 pData->CnrInfo.hptrExpanded = pci->hptrExpanded;
754 pData->CnrInfo.hptrCollapsed = pci->hptrCollapsed;
755
756 // @@todo recalc window components, repaint
757 }
758
759 if (flCI & CMA_LINESPACING)
760 {
761 // The amount of vertical space (in pels) between the records. If this value is
762 // less than 0, a default value is used.
763 pData->CnrInfo.cyLineSpacing = pci->cyLineSpacing;
764
765 // @@todo recalc window components, repaint
766 }
767
768 if (flCI & CMA_CXTREEINDENT)
769 {
770 // Horizontal distance (in pels) between levels in the tree view. If this value is
771 // less than 0, a default value is used.
772 pData->CnrInfo.cxTreeIndent = pci->cxTreeIndent;
773
774 // @@todo recalc window components, repaint
775 }
776
777 if (flCI & CMA_CXTREELINE)
778 {
779 // Width of the lines (in pels) that show the relationship between items in the
780 // tree view. If this value is less than 0, a default value is used. Also, if the
781 // CA_TREELINE container attribute of the CNRINFO data structure's
782 // flWindowAttr field is not specified, these lines are not drawn.
783 pData->CnrInfo.cxTreeLine = pci->cxTreeLine;
784 }
785
786 if (flCI & CMA_XVERTSPLITBAR)
787 {
788 // The initial position of the split bar relative to the container, used in the
789 // details view. If this value is less than 0, the split bar is not used. The default
790 // value is negative one (-1).
791 pData->CnrInfo.xVertSplitbar = pci->xVertSplitbar;
792 }
793
794 if (flDirty)
795 // post semaphore to force resize of details wnd
796 WinPostMsg(hwnd,
797 WM_SEM2,
798 (MPARAM)flDirty,
799 0);
800
801 return TRUE;
802 }
803
804 return FALSE;
805}
806
807/* ******************************************************************
808 *
809 * FIELDINFO-related messages
810 *
811 ********************************************************************/
812
813/*
814 *@@ CnrAllocDetailFieldInfo:
815 * implementation for CM_ALLOCDETAILFIELDINFO in fnwpCnr.
816 *
817 * Returns: PFIELDINFO linked list or NULL.
818 */
819
820PFIELDINFO CnrAllocDetailFieldInfo(HWND hwnd,
821 USHORT cFieldInfos) // in: no. of fieldinfos to allocate (> 0)
822{
823 PFIELDINFO pfiFirst = NULL,
824 pfiPrev = NULL;
825
826 PCNRDATA pData;
827 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
828 {
829 ULONG ul;
830 for (ul = 0;
831 ul < cFieldInfos;
832 ++ul)
833 {
834 // we must allocate each one separately or we cannot
835 // free them separately with CM_FREEDETAILFIELDINFO
836 PFIELDINFO pfiThis;
837 if (pfiThis = NEW(FIELDINFO))
838 {
839 ZERO(pfiThis);
840
841 // link into list
842 if (!pfiPrev)
843 // first round:
844 pfiFirst = pfiThis;
845 else
846 pfiPrev->pNextFieldInfo = pfiThis;
847
848 // put into private linklist
849 lstAppendItem(&pData->llAllocatedFIs,
850 pfiThis);
851
852 pfiPrev = pfiThis;
853 }
854 }
855 }
856
857 return pfiFirst;
858}
859
860/*
861 *@@ CnrInsertDetailFieldInfo:
862 * implementation for CM_INSERTDETAILFIELDINFO in fnwpCnr.
863 */
864
865USHORT CnrInsertDetailFieldInfo(HWND hwnd,
866 PFIELDINFO pfiFirst,
867 PFIELDINFOINSERT pfii)
868{
869 USHORT usrc = 0;
870 PCNRDATA pData;
871 if ( (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
872 && (pfiFirst)
873 && (pfii)
874 && (pfii->cb = sizeof(FIELDINFOINSERT))
875 )
876 {
877 ULONG ul;
878 PFIELDINFO pfiThis = pfiFirst;
879 PLISTNODE pNodeInsertAfter;
880
881 usrc = lstCountItems(&pData->llColumns);
882
883 switch ((ULONG)pfii->pFieldInfoOrder)
884 {
885 case CMA_FIRST:
886 pNodeInsertAfter = NULL; // first
887 break;
888
889 case CMA_END:
890 pNodeInsertAfter = lstQueryLastNode(&pData->llColumns);
891 // can return NULL also
892 break;
893
894 default:
895 if (!FindColumnFromFI(pData,
896 pfii->pFieldInfoOrder,
897 &pNodeInsertAfter))
898 pNodeInsertAfter = NULL;
899 }
900
901 for (ul = 0;
902 ul < pfii->cFieldInfoInsert;
903 ++ul)
904 {
905 PDETAILCOLUMN pdc;
906 if (pdc = NEW(DETAILCOLUMN))
907 {
908 ZERO(pdc);
909
910 pdc->pfi = pfiThis;
911
912 if (pNodeInsertAfter = lstInsertItemAfterNode(&pData->llColumns,
913 pdc,
914 pNodeInsertAfter))
915 {
916 ++usrc;
917 ++pData->CnrInfo.cFields;
918 pfiThis = pfiThis->pNextFieldInfo;
919 continue;
920 }
921 }
922
923 free(pdc);
924
925 usrc = 0;
926 break;
927
928 } // for (ul = 0; ul < pfii->cFieldInfoInsert; ...
929
930 if ( (usrc)
931 && (pfii->fInvalidateFieldInfo)
932 )
933 {
934 // post semaphore to force resize of details wnd
935 WinPostMsg(hwnd,
936 WM_SEM2,
937 (MPARAM)DDFL_ALL,
938 0);
939 }
940 }
941
942 return usrc;
943}
944
945/*
946 *@@ CnrInvalidateDetailFieldInfo:
947 * implementation for CM_INVALIDATEDETAILFIELDINFO in fnwpCnr.
948 */
949
950BOOL CnrInvalidateDetailFieldInfo(HWND hwnd)
951{
952 PCNRDATA pData;
953 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
954 {
955 WinPostMsg(hwnd,
956 WM_SEM2,
957 (MPARAM)DDFL_INVALIDATECOLUMNS,
958 0);
959 }
960
961 return FALSE;
962}
963
964/*
965 *@@ CnrRemoveDetailFieldInfo:
966 * implementation for CM_REMOVEDETAILFIELDINFO in fnwpCnr.
967 */
968
969SHORT CnrRemoveDetailFieldInfo(HWND hwnd,
970 PFIELDINFO* ppafi,
971 USHORT cfi,
972 USHORT fl)
973{
974 PCNRDATA pData;
975 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
976 {
977 SHORT rc = lstCountItems(&pData->llColumns);
978 ULONG fAnythingFound = FALSE,
979 ul;
980
981 for (ul = 0;
982 ul < cfi;
983 ++ul)
984 {
985 PDETAILCOLUMN pCol;
986 PLISTNODE pNodeCol;
987 if (!(pCol = FindColumnFromFI(pData,
988 ppafi[ul],
989 &pNodeCol)))
990 {
991 rc = -1;
992 break;
993 }
994
995 // found:
996 lstRemoveNode(&pData->llColumns,
997 pNodeCol); // auto-free, so this frees the DETAILCOLUMN
998
999 if (fl & CMA_FREE)
1000 lstRemoveItem(&pData->llAllocatedFIs,
1001 ppafi[ul]); // auto-free, so this frees the FIELDINFO
1002
1003 fAnythingFound = TRUE;
1004
1005 --rc;
1006 --pData->CnrInfo.cFields;
1007 }
1008
1009 if ( (fAnythingFound)
1010 && (fl & CMA_INVALIDATE)
1011 )
1012 {
1013 WinPostMsg(hwnd,
1014 WM_SEM2,
1015 (MPARAM)DDFL_INVALIDATECOLUMNS,
1016 0);
1017 }
1018
1019 return rc;
1020 }
1021
1022 return -1;
1023}
1024
1025/*
1026 *@@ CnrFreeDetailFieldInfo:
1027 * implementation for CM_FREEDETAILFIELDINFO in fnwpCnr.
1028 */
1029
1030BOOL CnrFreeDetailFieldInfo(HWND hwnd,
1031 PFIELDINFO *ppafi, // in: mp1 of CM_FREEDETAILFIELDINFO
1032 USHORT cFieldInfos) // in: no. of items in array
1033{
1034 BOOL brc = FALSE;
1035
1036 PCNRDATA pData;
1037 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
1038 {
1039 ULONG ul;
1040
1041 // @@todo return FALSE if the FI is currently inserted
1042
1043 if (1)
1044 {
1045 for (ul = 0;
1046 ul < cFieldInfos;
1047 ++ul)
1048 {
1049 PFIELDINFO pfiThis = ppafi[ul];
1050 lstRemoveItem(&pData->llAllocatedFIs,
1051 pfiThis);
1052 }
1053
1054 brc = TRUE;
1055 }
1056 }
1057
1058 return brc;
1059}
1060
1061/* ******************************************************************
1062 *
1063 * Record insertion/removal
1064 *
1065 ********************************************************************/
1066
1067/*
1068 *@@ CnrAllocRecord:
1069 * implementation for CM_ALLOCRECORD in fnwpCnr.
1070 */
1071
1072PRECORDCORE CnrAllocRecord(HWND hwnd,
1073 ULONG cbExtra,
1074 USHORT cRecords)
1075{
1076 PRECORDCORE preccFirst = NULL;
1077 PCNRDATA pData;
1078 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
1079 {
1080 ULONG ul;
1081 ULONG cbAlloc = ( (pData->fMiniRecords)
1082 ? sizeof(MINIRECORDCORE)
1083 : sizeof(RECORDCORE)
1084 ) + cbExtra;
1085
1086 PRECORDCORE preccPrev = NULL;
1087
1088 for (ul = 0;
1089 ul < cRecords;
1090 ++ul)
1091 {
1092 PRECORDCORE preccThis;
1093 if (!(preccThis = (PRECORDCORE)malloc(cbAlloc)))
1094 {
1095 preccFirst = NULL;
1096 break;
1097 }
1098
1099 memset(preccThis, 0, cbAlloc);
1100
1101 preccThis->cb = cbAlloc;
1102
1103 // link into list
1104 if (!preccPrev)
1105 // first round:
1106 preccFirst = preccThis;
1107 else
1108 preccPrev->preccNextRecord = preccThis;
1109
1110 // put into private linklist
1111 lstAppendItem(&pData->llAllocatedRecs,
1112 preccThis);
1113
1114 preccPrev = preccThis;
1115 }
1116 }
1117
1118 return preccFirst;
1119}
1120
1121/*
1122 *@@ CnrInsertRecord:
1123 * implementation for CM_INSERTRECORD in fnwpCnr.
1124 */
1125
1126ULONG CnrInsertRecord(HWND hwnd,
1127 PRECORDCORE preccFirst,
1128 PRECORDINSERT pri)
1129{
1130 ULONG cReturn = 0;
1131 PCNRDATA pData;
1132 if ( (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
1133 && (preccFirst)
1134 && (pri)
1135 && (pri->cb = sizeof(RECORDINSERT))
1136 )
1137 {
1138 PRECORDCORE preccThis = preccFirst;
1139 ULONG ul;
1140 PLINKLIST pll;
1141 PLISTNODE pNodeInsertAfter;
1142
1143 cReturn = lstCountItems(&pData->llRootRecords);
1144
1145 if (pri->pRecordParent)
1146 {
1147 // @@todo
1148 }
1149 else
1150 // insert at root:
1151 pll = &pData->llRootRecords;
1152
1153 switch ((ULONG)pri->pRecordOrder)
1154 {
1155 case CMA_FIRST:
1156 pNodeInsertAfter = NULL; // first
1157 break;
1158
1159 case CMA_END:
1160 pNodeInsertAfter = lstQueryLastNode(pll);
1161 // can return NULL also
1162 break;
1163
1164 default:
1165 pNodeInsertAfter = FindListNodeForRecc(pData,
1166 pri->pRecordOrder);
1167 }
1168
1169 for (ul = 0;
1170 ul < pri->cRecordsInsert;
1171 ++ul)
1172 {
1173 PRECORDLISTITEM pListItem;
1174
1175 if (pListItem = NEW(RECORDLISTITEM))
1176 {
1177 ZERO(pListItem);
1178
1179 pListItem->precc = preccThis;
1180 pListItem->preccParent = pri->pRecordParent;
1181
1182 if (pNodeInsertAfter = lstInsertItemAfterNode(pll,
1183 pListItem,
1184 pNodeInsertAfter))
1185 {
1186 PRECORDTREEITEM pTreeItem;
1187
1188 if (pTreeItem = NEW(RECORDTREEITEM))
1189 {
1190 ZERO(pTreeItem);
1191
1192 pTreeItem->Tree.ulKey = (ULONG)preccThis;
1193 pTreeItem->pListNode = pNodeInsertAfter; // newly created list node
1194
1195 // the following will fail if the record
1196 // is already inserted!
1197 if (!treeInsert(&pData->RecordsTree,
1198 (PLONG)&pData->CnrInfo.cRecords,
1199 (TREE*)pTreeItem,
1200 treeCompareKeys))
1201 {
1202 ++cReturn;
1203 preccThis = preccThis->preccNextRecord;
1204 continue;
1205 }
1206
1207 free(pTreeItem);
1208 }
1209
1210 lstRemoveNode(pll,
1211 pNodeInsertAfter);
1212 }
1213
1214 free(pListItem);
1215 }
1216
1217 free(pListItem);
1218
1219 cReturn = 0;
1220 break; // for
1221 } // for (ul = 0; ul < pri->cRecordsInsert; ...
1222
1223 if ( (cReturn)
1224 && (pri->fInvalidateRecord)
1225 )
1226 {
1227 WinPostMsg(hwnd,
1228 WM_SEM2,
1229 (MPARAM)DDFL_INCALIDATERECORDS,
1230 0);
1231 }
1232 }
1233
1234 return cReturn;
1235}
1236
1237/* ******************************************************************
1238 *
1239 * Container window proc
1240 *
1241 ********************************************************************/
1242
1243/*
1244 *@@ fnwpCnr:
1245 *
1246 */
1247
1248MRESULT EXPENTRY fnwpCnr(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1249{
1250 MRESULT mrc = 0;
1251 PCNRDATA pData;
1252
1253 switch (msg)
1254 {
1255 /* ******************************************************************
1256 *
1257 * Standard window messages
1258 *
1259 ********************************************************************/
1260
1261 case WM_CREATE:
1262 mrc = CnrCreate(hwnd, mp1, mp2);
1263 break;
1264
1265 case WM_SEM2:
1266 CnrSem2(hwnd, (ULONG)mp1);
1267 break;
1268
1269 case WM_PAINT:
1270 CnrPaint(hwnd);
1271 break;
1272
1273 case WM_WINDOWPOSCHANGED:
1274 mrc = CnrWindowPosChanged(hwnd, mp1, mp2);
1275 break;
1276
1277 case WM_HSCROLL:
1278 case WM_VSCROLL:
1279 CnrScroll(hwnd, msg, mp1, mp2);
1280 break;
1281
1282 case WM_DESTROY:
1283 CnrDestroy(hwnd);
1284 break;
1285
1286 /* ******************************************************************
1287 *
1288 * General container messages
1289 *
1290 ********************************************************************/
1291
1292 /*
1293 * CM_QUERYCNRINFO:
1294 *
1295 * Parameters:
1296 *
1297 * -- PCNRINFO mp1: buffer to copy to.
1298 * -- USHORT mp2: size of buffer.
1299 *
1300 * Returns no. of bytes copied or 0 on errors.
1301 */
1302
1303 case CM_QUERYCNRINFO:
1304 mrc = (MRESULT)CnrQueryCnrInfo(hwnd,
1305 (PCNRINFO)mp1,
1306 (USHORT)mp2);
1307 break;
1308
1309 /*
1310 * CM_SETCNRINFO:
1311 *
1312 * Parameters:
1313 *
1314 * -- PCNRINFO mp1: buffer to copy fields from.
1315 *
1316 * -- ULONG fl: CMA_* flags for fields that changed.
1317 *
1318 * Returns BOOL.
1319 */
1320
1321 case CM_SETCNRINFO:
1322 mrc = (MRESULT)CnrSetCnrInfo(hwnd,
1323 (PCNRINFO)mp1,
1324 (ULONG)mp2);
1325 break;
1326
1327 /* ******************************************************************
1328 *
1329 * FIELDINFO-related messages
1330 *
1331 ********************************************************************/
1332
1333 /*
1334 * CM_ALLOCDETAILFIELDINFO:
1335 *
1336 * Parameters:
1337 *
1338 * -- USHORT mp1: no. of fieldinfos to allocate
1339 * -- mp2: reserved
1340 *
1341 * Returns PFIELDINFO linked list of fieldinfos,
1342 * or NULL on errors.
1343 */
1344
1345 case CM_ALLOCDETAILFIELDINFO:
1346 mrc = (MRESULT)CnrAllocDetailFieldInfo(hwnd,
1347 (USHORT)mp1);
1348 break;
1349
1350 /*
1351 * CM_INSERTDETAILFIELDINFO:
1352 *
1353 * Parameters:
1354 *
1355 * -- PFIELDINFO mp1
1356 *
1357 * -- PFIELDINFOINSERT mp2
1358 *
1359 * Returns the no. of FI's in the cnr or 0 on errors.
1360 */
1361
1362 case CM_INSERTDETAILFIELDINFO:
1363 mrc = (MRESULT)CnrInsertDetailFieldInfo(hwnd,
1364 (PFIELDINFO)mp1,
1365 (PFIELDINFOINSERT)mp2);
1366 break;
1367
1368 /*
1369 * CM_INVALIDATEDETAILFIELDINFO:
1370 * No parameters.
1371 *
1372 * Returns BOOL.
1373 */
1374
1375 case CM_INVALIDATEDETAILFIELDINFO:
1376 mrc = (MRESULT)CnrInvalidateDetailFieldInfo(hwnd);
1377 break;
1378
1379 /*
1380 * CM_REMOVEDETAILFIELDINFO:
1381 *
1382 * Parameters:
1383 *
1384 * -- PFIELDINFO* mp1: ptr to array of PFIELDINFO's
1385 *
1386 * -- SHORT1FROMMP(mp1): no. of fieldinfos in array
1387 *
1388 * -- SHORT2FROMMP(mp2): flRemove (CMA_FREE, CMA_INVALIDATE)
1389 *
1390 * Returns the no. of FI's in the cnr or -1 on errors.
1391 */
1392
1393 case CM_REMOVEDETAILFIELDINFO:
1394 mrc = (MRESULT)CnrRemoveDetailFieldInfo(hwnd,
1395 (PFIELDINFO*)mp1,
1396 SHORT1FROMMP(mp2),
1397 SHORT2FROMMP(mp2));
1398 break;
1399
1400 /*
1401 * CM_FREEDETAILFIELDINFO:
1402 *
1403 * Paramters:
1404 *
1405 * -- PFIELDINFO* mp1: ptr to array of PFIELDINFO's
1406 * -- USHORT mp2: no. of ptrs in array
1407 *
1408 * Returns BOOL.
1409 */
1410
1411 case CM_FREEDETAILFIELDINFO:
1412 mrc = (MRESULT)CnrFreeDetailFieldInfo(hwnd,
1413 (PFIELDINFO*)mp1,
1414 (USHORT)mp2);
1415 break;
1416
1417 /* ******************************************************************
1418 *
1419 * Record allocation/insertion/removal
1420 *
1421 ********************************************************************/
1422
1423 /*
1424 * CM_ALLOCRECORD:
1425 *
1426 * Parameters:
1427 *
1428 * -- ULONG mp1: record size in addition to (MINI)RECORDCORE size.
1429 *
1430 * -- USHORT mp2: no. of records to allocate.
1431 *
1432 * Returns linked list of RECORDCORE's or NULL on errors.
1433 */
1434
1435 case CM_ALLOCRECORD:
1436 mrc = (MRESULT)CnrAllocRecord(hwnd,
1437 (ULONG)mp1,
1438 (USHORT)mp2);
1439 break;
1440
1441 /*
1442 * CM_INSERTRECORD:
1443 *
1444 * Parameters:
1445 *
1446 * -- PRECORDCORE mp1: first record
1447 *
1448 * -- PRECORDINSERT pri
1449 *
1450 * Returns the no. of records in the container or 0 on errors.
1451 */
1452
1453 case CM_INSERTRECORD:
1454 mrc = (MRESULT)CnrInsertRecord(hwnd,
1455 (PRECORDCORE)mp1,
1456 (PRECORDINSERT)mp2);
1457 break;
1458
1459 default:
1460 if (pData = (PCNRDATA)WinQueryWindowPtr(hwnd, QWL_USER + 1))
1461 mrc = ctlDefWindowProc(&pData->dwdMain, msg, mp1, mp2);
1462 break;
1463
1464 }
1465
1466 return mrc;
1467}
1468
1469/*
1470 *@@ ctlRegisterXCnr:
1471 *
1472 */
1473
1474BOOL ctlRegisterXCnr(HAB hab)
1475{
1476 return ( WinRegisterClass(hab,
1477 WC_CCTL_CNR,
1478 fnwpCnr,
1479 0, // CS_SYNCPAINT, // CS_CLIPSIBLINGS CS_CLIPCHILDREN
1480 sizeof(PVOID) * 2)
1481 && WinRegisterClass(hab,
1482 WC_CCTL_CNR_DETAILS,
1483 fnwpCnrDetails,
1484 0, // CS_SYNCPAINT, // | CS_PARENTCLIP, // CS_CLIPSIBLINGS CS_CLIPCHILDREN
1485 sizeof(PVOID) * 2)
1486 );
1487}
1488
Note: See TracBrowser for help on using the repository browser.