source: trunk/src/helpers/cnrh.c@ 68

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

misc changes

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 78.3 KB
Line 
1
2/*
3 *@@sourcefile cnrh.c:
4 * contains various PM container helper functions.
5 *
6 * These functions used to be in winh.c, but they became
7 * too many finally, so these were moved to this file with
8 * V0.9.0.
9 *
10 * Usage: All PM programs.
11 *
12 * Function prefixes:
13 * -- cnrh* container helper functions (was: winh* before V0.9.0)
14 *
15 * Note: Version numbering in this file relates to XWorkplace version
16 * numbering.
17 *
18 *@@added V0.9.0 [umoeller]
19 *@@header "helpers\cnrh.h"
20 */
21
22/*
23 * Copyright (C) 1997-2000 Ulrich M”ller.
24 * This file is part of the "XWorkplace helpers" source package.
25 * This is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published
27 * by the Free Software Foundation, in version 2 as it comes in the
28 * "COPYING" file of the XWorkplace main distribution.
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
33 */
34
35#define OS2EMX_PLAIN_CHAR
36 // this is needed for "os2emx.h"; if this is defined,
37 // emx will define PSZ as _signed_ char, otherwise
38 // as unsigned char
39
40#define INCL_WINWINDOWMGR
41#define INCL_WINRECTANGLES
42#define INCL_WININPUT
43#define INCL_WINPOINTERS
44#define INCL_WINMENUS
45#define INCL_WINSYS
46#define INCL_WINSTDDRAG
47#define INCL_WINSTDCNR
48
49#define INCL_GPILOGCOLORTABLE
50#define INCL_GPIPRIMITIVES
51#include <os2.h>
52
53#include <stdlib.h>
54#include <string.h>
55#include <stdio.h>
56
57#include "setup.h" // code generation and debugging options
58
59#include "helpers\winh.h"
60#include "helpers\cnrh.h"
61
62#pragma hdrstop
63
64/*
65 *@@category: Helpers\PM helpers\Container helpers
66 * See cnrh.c.
67 */
68
69/*
70 *@@category: Helpers\PM helpers\Container helpers\Details view helpers
71 * these functions aid you in setting up the FIELDINFO structures
72 * for a container Details view. Use cnrhSetFieldInfos for that.
73 */
74
75/* ******************************************************************
76 *
77 * Details view field infos
78 *
79 ********************************************************************/
80
81/*
82 *@@ cnrhClearFieldInfos:
83 * removes all existing FIELDINFO's from
84 * the given container. Returns the number
85 * of remaining FIELDINFO's, which should
86 * be 0, or -1 upon errors.
87 *
88 *@@added V0.9.1 (2000-02-13) [umoeller]
89 */
90
91ULONG cnrhClearFieldInfos(HWND hwndCnr,
92 BOOL fInvalidate) // in: if TRUE, invalidate container
93{
94 ULONG ulFlags = CMA_FREE;
95 if (fInvalidate)
96 ulFlags |= CMA_INVALIDATE;
97
98 return (ULONG)(WinSendMsg(hwndCnr,
99 CM_REMOVEDETAILFIELDINFO,
100 (MPARAM)NULL,
101 MPFROM2SHORT(0, // all
102 ulFlags)));
103}
104
105/*
106 *@@ cnrhSetFieldInfo:
107 * this sets a FIELDINFO structure to the given
108 * data. Note that ppFieldInfo is a double pointer
109 * to the actual FIELDINFO data.
110 *
111 * This gets called from cnrhSetFieldInfos to set
112 * each individual field info.
113 * You can also use this function separately with
114 * the cnrhAllocFieldInfos macro defined in cnrh.h.
115 *
116 * After setting the data, <B>*ppFieldInfo</B> is advanced
117 * to the next FIELDINFO structure so that you can
118 * call this function several times for all the
119 * FIELDINFOS that you have allocated. After the last
120 * column, this pointer will be NULL.
121 *
122 * Since the pointer is modified, do not invoke this
123 * function on the original pointer returned from
124 * cnrhAllocFieldInfos, because you'll need that
125 * pointer for cnrhAllocFieldInfos later.
126 *
127 * <B>Example usage</B>:
128 *
129 + PFIELDINFO pFieldInfoFirst, pFieldInfo2;
130 + if (pFieldInfoFirst = cnrhAllocFieldInfos(hwndFilesCnr, NO_OF_COLUMNS))
131 + // macro defined in cnrh.h
132 + {
133 + pFieldInfo2 = pFieldInfoFirst;
134 +
135 + // "File name" column
136 + cnrhSetFieldInfo(&pFieldInfo2,
137 + FIELDOFFSET(RECORDCORE, pszIcon),
138 + // icon text offset in original RECORDCORE
139 + "File name",
140 + CFA_STRING,
141 + CFA_LEFT,
142 + FALSE); // no draw lines
143 + // "Size" column
144 + cnrhSetFieldInfo(&pFieldInfo2,
145 + FIELDOFFSET(FILERECORDCORE, ulSize),
146 + // size data field in sample extended RECORDCORE
147 + "Size",
148 + CFA_ULONG,
149 + CFA_RIGHT,
150 + FALSE); // no draw lines
151 + ... // set other field infos
152 + }
153 +
154 + // insert field infos
155 + cnrhInsertFieldInfos(hwndFilesCnr,
156 + pFieldInfoFirst,
157 + NO_OF_COLUMNS);
158 *
159 *@@added V0.9.0 [umoeller]
160 *@@changed V0.9.1 (99-12-18) [umoeller]: fixed memory leak
161 */
162
163VOID cnrhSetFieldInfo(PFIELDINFO *ppFieldInfo2, // in/out: double ptr to FIELDINFO
164 ULONG ulFieldOffset, // in: FIELDOFFSET(YOURRECORDCORE, yourField)
165 PSZ pszColumnTitle, // in: column title; this must be a static string!!
166 ULONG ulDataType, // in: column data type (CFA_* flags)
167 ULONG ulOrientation, // in: vertical and horizontal orientation (CFA_* flags)
168 BOOL fDrawLines) // in: if TRUE, we'll draw lines around the columns
169{
170 if (ppFieldInfo2)
171 if (*ppFieldInfo2)
172 {
173 ULONG flData = ulDataType | ulOrientation;
174 if (fDrawLines)
175 flData |= CFA_HORZSEPARATOR | CFA_SEPARATOR;
176
177 (*ppFieldInfo2)->cb = sizeof(FIELDINFO);
178 (*ppFieldInfo2)->flData = flData;
179 (*ppFieldInfo2)->flTitle = CFA_FITITLEREADONLY | ulOrientation;
180 (*ppFieldInfo2)->offStruct = ulFieldOffset;
181 (*ppFieldInfo2)->pTitleData = pszColumnTitle; // strdup removed, V0.9.1 (99-12-18) [umoeller]
182 (*ppFieldInfo2)->pUserData = NULL;
183 *ppFieldInfo2 = (*ppFieldInfo2)->pNextFieldInfo;
184 }
185}
186
187/*
188 *@@ cnrhInsertFieldInfos:
189 * this inserts field infos for Details view
190 * into the specified container.
191 *
192 * pFieldInfoFirst should be the PFIELDINFO
193 * returned by cnrhAllocFieldInfos.
194 *
195 * This inserts the FIELDINFOs at the end,
196 * should any columns already exist in the container.
197 * Also, the container is invalidated.
198 *
199 * Returns the return value of CM_INSERTDETAILFIELDINFO,
200 * which is the total no. of field infos in the container
201 * or null upon errors.
202 *
203 *@@added V0.9.0 [umoeller]
204 */
205
206ULONG cnrhInsertFieldInfos(HWND hwndCnr, // in: cnr for Details view
207 PFIELDINFO pFieldInfoFirst, // in: first field info as returned
208 // by cnrhAllocFieldInfos
209 ULONG ulFieldCount) // in: no. of field infos
210{
211 FIELDINFOINSERT fii;
212 fii.cb = sizeof(FIELDINFOINSERT);
213 fii.pFieldInfoOrder = (PFIELDINFO)CMA_END;
214 fii.fInvalidateFieldInfo = TRUE;
215 fii.cFieldInfoInsert = ulFieldCount;
216
217 return ((ULONG)WinSendMsg(hwndCnr,
218 CM_INSERTDETAILFIELDINFO,
219 (MPARAM)pFieldInfoFirst,
220 (MPARAM)&fii));
221}
222
223/*
224 *@@ cnrhSetFieldInfos:
225 * this combines cnrhAllocFieldInfos,
226 * cnrhSetFieldInfo, and cnrhInsertFieldInfos
227 * into a one-shot func for setting details view
228 * column field infos. This one has proven to
229 * be EXTREMELY useful.
230 *
231 * To pass all the arguments normally passed to
232 * cnrhSetFieldInfo, we use an array of XFIELDINFO
233 * structures, which takes the same parameters.
234 *
235 * <B>XFIELDINFO.ulDataType</B> specifies the data type of the record
236 * core field. This can be one of the following:
237 * -- CFA_BITMAPORICON: bit-map or icon data
238 * -- CFA_DATE: date format (CDATE structure)
239 * -- CFA_STRING: null-terminated string
240 * -- CFA_TIME: time format (CTIME structure)
241 * -- CFA_ULONG: unsigned number data
242 *
243 * You can add the following optional flags to
244 * ulDataType:
245 * -- CFA_FIREADONLY (CFA_STRING only): disable editing
246 * -- CFA_INVISIBLE: make column invisible
247 * -- CFA_OWNER: enable owner draw for this column
248 *
249 * If (fDrawLines == TRUE), we'll automatically add
250 * CFA_HORZSEPARATOR | CFA_SEPARATOR.
251 *
252 * <B>XFIELDINFO.ulOrientation</B> specifies the vertical and
253 * horizontal orientation of both the column title
254 * and the column data. This should be OR'ed from
255 * the following
256 * -- CFA_CENTER, CFA_LEFT, CFA_RIGHT (horizontal);
257 * the default is CFA_LEFT
258 * -- CFA_BOTTOM, CFA_TOP, CFA_VCENTER (vertical);
259 * the default is CFA_VCENTER.
260 *
261 * Note that the container automatically displays
262 * data according to the settings in the "Country" object.
263 *
264 * The column title will always be set to string format
265 * and CFA_FITITLEREADONLY.
266 *
267 * <B>XFIELDINFO.ulFieldOffset</B> should be set to the return value
268 * of the FIELDOFFSET macro, which is also redefined in
269 * cnrh.h (to work with C++).
270 *
271 * The return value is the PFIELDINFO which corresponds
272 * to the column index specified in ulFieldReturn, or
273 * NULL upon errors. This is useful for setting the
274 * position of the split bar afterwards (using the
275 * cnrhSetSplitBarAfter macro).
276 *
277 * Example usage:
278 + XFIELDINFO xfi[3];
279 + PFIELDINFO pfi;
280 +
281 + xfi[0].ulFieldOffset = FIELDOFFSET(DATABASERECORD, pszApplication);
282 + xfi[0].pszColumnTitle = "Application";
283 + xfi[0].ulDataType = CFA_STRING;
284 + xfi[0].ulOrientation = CFA_LEFT;
285 +
286 + xfi[1].ulFieldOffset = FIELDOFFSET(RECORDCORE, pszIcon);
287 + xfi[1].pszColumnTitle = "Package name";
288 + xfi[1].ulDataType = CFA_STRING;
289 + xfi[1].ulOrientation = CFA_LEFT;
290 +
291 + xfi[2].ulFieldOffset = FIELDOFFSET(DATABASERECORD, pszAuthor);
292 + xfi[2].pszColumnTitle = "Author";
293 + xfi[2].ulDataType = CFA_STRING;
294 + xfi[2].ulOrientation = CFA_CENTER;
295 +
296 + pfi = cnrhSetFieldInfos(hwndCnr,
297 + &xfi[0],
298 + (sizeof(xfi) / sizeof(XFIELDINFO)),
299 + // smart way of calculating the array item count
300 + FALSE, // no draw lines
301 + 0); // return first column
302 *
303 *@@added V0.9.0 [umoeller]
304 */
305
306PFIELDINFO cnrhSetFieldInfos(HWND hwndCnr, // in: container hwnd
307 PXFIELDINFO paxfi, // in: pointer to an array of ulFieldCount XFIELDINFO structures
308 ULONG ulFieldCount, // in: no. of items in paxfi array (> 0)
309 BOOL fDrawLines, // in: if TRUE, we'll draw lines around the columns
310 ULONG ulFieldReturn) // in: the column index to return as PFIELDINFO
311{
312 PFIELDINFO pFieldInfoFirst,
313 pFieldInfo2,
314 pFieldInfoReturn = NULL;
315
316 if ((pFieldInfoFirst = cnrhAllocFieldInfos(hwndCnr, ulFieldCount)))
317 {
318 ULONG ul = 0;
319 PXFIELDINFO pxfi = NULL;
320
321 pFieldInfo2 = pFieldInfoFirst;
322 pxfi = paxfi;
323 for (ul = 0; ul < ulFieldCount; ul++)
324 {
325 if (ul == ulFieldReturn)
326 // set return value
327 pFieldInfoReturn = pFieldInfo2;
328
329 // set current field info;
330 // this will modify pFieldInfo to point to the next
331 cnrhSetFieldInfo(&pFieldInfo2,
332 pxfi->ulFieldOffset,
333 pxfi->pszColumnTitle,
334 pxfi->ulDataType,
335 pxfi->ulOrientation,
336 fDrawLines);
337 pxfi++;
338 }
339
340 // insert field infos
341 if (cnrhInsertFieldInfos(hwndCnr,
342 pFieldInfoFirst,
343 ulFieldCount) == 0)
344 pFieldInfoReturn = NULL;
345 }
346
347 return (pFieldInfoReturn);
348}
349
350/*
351 *@@category: Helpers\PM helpers\Container helpers\Record core helpers
352 * functions for allocating and inserting records more easily.
353 *
354 * Use cnrhAllocRecords first to allocate, then cnrhInsertRecords
355 * to insert the records.
356 */
357
358/* ******************************************************************
359 *
360 * Record core management
361 *
362 ********************************************************************/
363
364/*
365 *@@ cnrhAllocRecords:
366 * this is a shortcut to allocating memory for
367 * container record cores.
368 *
369 * If (ulCount == 1), this returns the new record core.
370 * If (ulCount > 1), this returns the _first_ record
371 * core; the following record cores may be reached
372 * by following the RECORDCORE.preccNextRecord pointers
373 * (i.e. we have a linked list here).
374 *
375 * Returns NULL on errors (what CM_ALLOCRECORD returns).
376 *
377 * The record cores returned by the container are
378 * automatically zeroed out, and their "cb" field
379 * is automatically set to the size of the record core.
380 *
381 * Note that this function presently does _not_ work
382 * with MINIRECORDCOREs.
383 *
384 *@@changed V0.9.0 [umoeller]: function prototype changed to allocate more than one record
385 */
386
387PRECORDCORE cnrhAllocRecords(HWND hwndCnr, // in: cnr to allocate from
388 ULONG cbrecc,
389 // in: total size of your record core.
390 // If you're using the default recc's, this
391 // must be sizeof(RECORDCORE).
392 ULONG ulCount) // in: number of records to allocate (> 0)
393{
394 PRECORDCORE precc;
395 precc = (PRECORDCORE)WinSendMsg(hwndCnr,
396 CM_ALLOCRECORD,
397 (MPARAM)(cbrecc-sizeof(RECORDCORE)),
398 (MPARAM)ulCount);
399
400 return (precc);
401}
402
403/*
404 *@@ cnrhInsertRecords:
405 * shortcut to inserting record cores into a container
406 * which have been allocated using cnrhAllocRecords.
407 *
408 * If (<B>ulCount</B> == 1), this inserts precc.
409 * If (ulCount > 1), this assumes precc to be the first
410 * record to be inserted, while precc->preccNextRecord
411 * must point to the next record in a linked list (as
412 * returned with cnrhAllocRecords). (changed V0.9.0)
413 *
414 * Note that ulCount here must be exactly the same as
415 * specified with cnrhAllocRecords.
416 *
417 * If (<B>pszText</B> != NULL), this will automatically set precc->pszIcon,
418 * precc->pszText, precc->pszName, precc->pszTree to pszText to have
419 * the same record titles in all views. If (pszText == NULL), those
420 * fields will be left alone. (changed V0.9.0)
421 *
422 * <B>flRecordAttr</B> should have the record attributes as
423 * specified in the RECORDCORE structure.
424 *
425 * Emphasis flags:
426 * -- CRA_SELECTED: record is selected
427 * (other records will be deselected in Tree views
428 * and when single selection is enabled)
429 * -- CRA_CURSORED: cursor (keyboard focus) is on the record
430 * (other records will be de-cursored)
431 * -- CRA_SOURCE: record has source emphasis (drag'n'drop,
432 * open context menus)
433 * -- CRA_TARGET: record has target emphasis (drag'n'drop)
434 * -- CRA_PICKED: record picked (Lazy Drag)
435 * -- CRA_INUSE: record has in-use emphasis (diagonal lines,
436 * as with open objects with the WPS)
437 *
438 * Miscellaneous flags:
439 * -- CRA_FILTERED: record has been filtered (is invisible)
440 * -- CRA_DROPONABLE: record can be dropped something upon
441 * -- CRA_RECORDREADONLY: record is read-only (no text edit with Alt+MB1)
442 * -- CRA_EXPANDED: record is expanded (Tree view)
443 * -- CRA_COLLAPSED: record is collapsed (Tree view)
444 *
445 * plus the following half-documented from PMSTDDLG.H (haven't tested these):
446 * -- CRA_IGNORE record is to be ignored
447 * -- CRA_DISABLED has no visible effect, but can be used with
448 * cnrhOwnerDrawRecord
449 * -- CRA_LOCKED maybe "locked in place"?!?
450 * -- CRA_OWNERFREE owner must free record
451 * -- CRA_OWNERDRAW owner must draw record; I'd recommend using
452 * CA_OWNERDRAW in CNRINFO.flWindowAttr instead.
453 *
454 * This func returns the total number of records in the container
455 * or NULL upon errors (return value of CM_INSERTRECORD, changed V0.9.0).
456 *
457 *@@changed V0.9.0 [umoeller]: function prototype changed to insert more than one record
458 *@@changed V0.9.0 [umoeller]: added error checking for pszText
459 *@@changed V0.9.2 (2000-02-19) [umoeller]: added fInvalidate field
460 */
461
462ULONG cnrhInsertRecords(HWND hwndCnr, // in: container to insert into
463 PRECORDCORE preccParent,
464 // in: record core below which precc should
465 // be inserted (tree view only). If NULL, precc
466 // is inserted at "root" level
467 PRECORDCORE precc,
468 // in: record core to insert (allocated using
469 // cnrhAllocRecords)
470 BOOL fInvalidate,
471 const char *pcszText,
472 // in: text for recc. in all views (or NULL)
473 ULONG flRecordAttr,
474 // in: CRA_* flags
475 ULONG ulCount) // in: number of records to insert (> 0)
476{
477 ULONG ulrc = 0;
478 RECORDINSERT ri;
479
480 if (precc)
481 {
482 // RECORDCORE stuff
483 precc->flRecordAttr = flRecordAttr;
484 // precc->preccNextRecord = NULL;
485
486 if (pcszText) // V0.9.0
487 {
488 precc->pszIcon = (PSZ)pcszText;
489 precc->pszText = (PSZ)pcszText;
490 precc->pszName = (PSZ)pcszText;
491 precc->pszTree = (PSZ)pcszText;
492 }
493
494 // setup RECORDINSERT struct
495 ri.cb = sizeof(RECORDINSERT);
496 ri.pRecordOrder = (PRECORDCORE)CMA_END;
497 ri.pRecordParent = (PRECORDCORE)preccParent;
498 ri.zOrder = CMA_TOP;
499 ri.fInvalidateRecord = fInvalidate; // V0.9.2 (2000-02-19) [umoeller]
500 ri.cRecordsInsert = ulCount; // V0.9.0
501
502 ulrc = (ULONG)WinSendMsg(hwndCnr,
503 CM_INSERTRECORD,
504 (MPARAM)precc,
505 (MPARAM)&ri);
506 }
507 return (ulrc);
508}
509
510/*
511 *@@ cnrhInsertRecordAfter:
512 * similar to cnrhInsertRecords, but this inserts
513 * a single record _after_ another one. Parent records
514 * and multiple records are not supported.
515 *
516 *@@added V0.9.0 [umoeller]
517 *@@changed V0.9.4 (2000-06-14) [umoeller]: added fInvalidate
518 */
519
520ULONG cnrhInsertRecordAfter(HWND hwndCnr,
521 PRECORDCORE precc,
522 PSZ pszText,
523 ULONG flRecordAttr,
524 PRECORDCORE preccAfter,
525 BOOL fInvalidate) // in: invalidate records?
526{
527 ULONG ulrc = 0;
528 RECORDINSERT ri;
529
530 if (precc)
531 {
532 // RECORDCORE stuff
533 precc->flRecordAttr = flRecordAttr;
534 precc->preccNextRecord = NULL;
535
536 if (pszText) // V0.9.0
537 {
538 precc->pszIcon = pszText;
539 precc->pszText = pszText;
540 precc->pszName = pszText;
541 precc->pszTree = pszText;
542
543 // setup RECORDINSERT struct
544 ri.cb = sizeof(RECORDINSERT);
545 ri.pRecordOrder = (PRECORDCORE)preccAfter;
546 ri.pRecordParent = 0; // no parent here
547 ri.zOrder = CMA_TOP;
548 ri.fInvalidateRecord = fInvalidate; // V0.9.4 (2000-06-14) [umoeller]
549 ri.cRecordsInsert = 1;
550
551 ulrc = (ULONG)WinSendMsg(hwndCnr,
552 CM_INSERTRECORD,
553 (MPARAM)precc,
554 (MPARAM)&ri);
555 }
556 }
557 return (ulrc);
558}
559
560/*
561 *@@ cnrhMoveRecord:
562 * this moves a single record within the same container
563 * window. This only makes sense in ordered views (i.e.
564 * Name, Text, and Details views).
565 *
566 * For moving records with child records, use cnrhMoveTree
567 * instead.
568 */
569
570BOOL cnrhMoveRecord(HWND hwndCnr,
571 PRECORDCORE preccMove, // in: record to move
572 PRECORDCORE preccInsertAfter)
573 // in: where to move the record to
574 // (can be CMA_FIRST or CMA_END)
575{
576 // rule out possible errors:
577 if ( (preccMove) // this better be valid
578 && (preccInsertAfter) // this also, because otherwise the record just disappears
579 && (preccMove != preccInsertAfter)
580 // same here
581 )
582 {
583 RECORDINSERT ri;
584 ULONG ulrc = 0;
585
586 // remove record
587 WinSendMsg(hwndCnr,
588 CM_REMOVERECORD,
589 (MPARAM)(&preccMove),
590 MPFROM2SHORT(1,
591 CMA_INVALIDATE)); // no free
592
593 // and re-insert that record at the new position
594 ri.cb = sizeof(RECORDINSERT);
595 ri.pRecordOrder = (PRECORDCORE)preccInsertAfter;
596 ri.pRecordParent = 0; // no parent here
597 ri.zOrder = CMA_TOP;
598 ri.fInvalidateRecord = TRUE;
599 ri.cRecordsInsert = 1;
600 ulrc = (ULONG)WinSendMsg(hwndCnr,
601 CM_INSERTRECORD,
602 (MPARAM)preccMove,
603 (MPARAM)&ri);
604
605 return (ulrc != 0);
606 }
607 else return (FALSE);
608}
609
610/*
611 *@@ cnrhMoveTree:
612 * this function moves a container record core and all its
613 * children from one tree to another.
614 * See the CM_MOVETREE message for more explanations.
615 *
616 * The problem with that message is that automatic container
617 * sorting does not work in tree view. This function however
618 * is smart enough to maintain container sorting and insert
619 * the moved record core at the correct position below the
620 * target record core, if you specify a container sort function
621 * (pfnCnrSort, which works just in CNRINFO).
622 *
623 * Otherwise, we'll just insert the item as the first child
624 * of preccNewParent.
625 *
626 * This function also has a workaround for a nasty container
627 * bug which results in a crash in PMMERGE.DLL when a tree
628 * is moved to the last position in the target parent record
629 * (at least with Warp 4 FP 7).
630 *
631 *@@added V0.9.0 [umoeller]
632 */
633
634BOOL cnrhMoveTree(HWND hwndCnr, // in: container control
635 PRECORDCORE preccMove, // in: record core to move
636 PRECORDCORE preccNewParent, // in: new parent for preccMove
637 // or NULL if move to root
638 PFNCNRSORT pfnCnrSort) // in: sort function to use or NULL
639{
640 TREEMOVE tm;
641 PRECORDCORE preccInsertAfter = (PRECORDCORE)CMA_FIRST;
642 BOOL fBugWorkAround = FALSE,
643 brc = FALSE;
644
645 if (pfnCnrSort)
646 {
647 // permanent sort activated:
648
649 // since the automatic container sort does
650 // not work when moving a record core tree in
651 // Tree view, we must find the recc after
652 // which we'll insert the tree ourselves
653 PRECORDCORE preccSearch = preccNewParent;
654 BOOL fFirstRun = TRUE;
655 ULONG ulFirstCode;
656
657 // set the code for first-loop query:
658 if (preccNewParent)
659 // if new parent is non-root
660 ulFirstCode = CMA_FIRSTCHILD;
661 else
662 // if new parent is root
663 ulFirstCode = CMA_FIRST;
664
665 while (TRUE)
666 {
667 preccSearch =
668 (PRECORDCORE)WinSendMsg(hwndCnr,
669 CM_QUERYRECORD,
670 // the following gets either the
671 // first child recc of the target
672 // record core or the next child
673 // for consecutive loops
674 (MPARAM)preccSearch,
675 MPFROM2SHORT(
676 ((fFirstRun)
677 ? ulFirstCode // first loop
678 : CMA_NEXT // works for next child too
679 ),
680 CMA_ITEMORDER)
681 );
682 fFirstRun = FALSE;
683
684 if ( (preccSearch == NULL)
685 || ((ULONG)preccSearch == -1)
686 )
687 {
688 // no more items found:
689 // keep preccInsertAfter, which might be CMA_FIRST
690 // or the preccSearch we have found previously.
691
692 if (preccInsertAfter != (PRECORDCORE)CMA_FIRST)
693 {
694 // Unfortunately, there is a bug in the container
695 // control which prohibits CM_MOVETREE from working
696 // if preccInsertAfter turns out to be the last
697 // record core in preccNewParent. This applies to
698 // preccInsertAfter == CMA_LAST also, and CMA_LASTCHILD
699 // doesn't work either.
700 // Duh.
701 // We'll fix this later.
702
703 fBugWorkAround = TRUE;
704 }
705 break;
706 }
707
708 if (((*pfnCnrSort)(preccSearch, preccMove, 0)) < 0)
709 {
710 // found record core is < our tree:
711 // mark current as "insert after" for later and go on
712 preccInsertAfter = preccSearch;
713 }
714 else
715 break;
716 }
717
718 /* _Pmpf(("preccInsertAfter %s",
719 (preccInsertAfter == (PRECORDCORE)CMA_FIRST) ? "CMA_FIRST"
720 : (preccInsertAfter == (PRECORDCORE)CMA_LAST) ? "CMA_LAST"
721 : (preccInsertAfter == NULL) ? "NULL"
722 : preccInsertAfter->pszIcon
723 )); */
724 } // end if (CnrInfo.pSortRecord)
725
726 if (fBugWorkAround)
727 // this is TRUE only if preccInsertAfter has turned
728 // out to be the last child of preccNewParent. This
729 // will make the container crash, so we insert as
730 // first and sort the whole damn container later.
731 // Not terribly fast, but better than crashing. ;-)
732 preccInsertAfter = (PRECORDCORE)CMA_FIRST;
733
734 // set record to be moved
735 tm.preccMove = preccMove;
736 // set target record core
737 tm.preccNewParent = preccNewParent;
738 tm.pRecordOrder = preccInsertAfter;
739 tm.flMoveSiblings = FALSE;
740 // move only preccMove
741 brc = (BOOL)WinSendMsg(hwndCnr,
742 CM_MOVETREE,
743 (MPARAM)&tm,
744 (MPARAM)NULL);
745
746 if (brc)
747 if (fBugWorkAround)
748 WinSendMsg(hwndCnr, CM_SORTRECORD, (MPARAM)pfnCnrSort, (MPARAM)NULL);
749
750 return (brc);
751}
752
753/*
754 *@@category: Helpers\PM helpers\Container helpers\View management
755 * functions for easily managing container views.
756 *
757 * Most importantly, this has the BEGIN_CNRINFO and END_CNRINFO
758 * macros which make CNRINFO handling easier. Also see
759 * cnrhSetView for that.
760 */
761
762/* ******************************************************************
763 *
764 * View management
765 *
766 ********************************************************************/
767
768/*
769 *@@ cnrhSelectAll:
770 * this selects or deselects all records in hwndCnr,
771 * depending on fSelect. Since multiple selections are
772 * not supported in Tree views in the first place, we
773 * only go for the "root" records (and no child records).
774 *
775 * Invoking this function on a container in Tree view
776 * will result in not much but display flickering anyway.
777 *
778 * This returns the number of records which were processed.
779 */
780
781ULONG cnrhSelectAll(HWND hwndCnr,
782 BOOL fSelect)
783{
784 ULONG ulrc = 0;
785 PRECORDCORE precc2 = NULL;
786
787 do {
788 precc2 =
789 (PRECORDCORE)WinSendMsg(hwndCnr,
790 CM_QUERYRECORD,
791 (MPARAM)precc2,
792 MPFROM2SHORT(
793 ((precc2 == NULL) ? CMA_FIRST : CMA_NEXT),
794 CMA_ITEMORDER)
795 );
796 if ((precc2 == 0) || ((LONG)precc2 == -1))
797 // last record or error:
798 break;
799
800 // select this one
801 cnrhSelectRecord(hwndCnr, precc2, fSelect);
802 ulrc++;
803
804 } while (TRUE);
805
806 return (ulrc);
807}
808
809/*
810 *@@ cnrhFindRecordFromPoint:
811 * this returns the record under the given
812 * point or NULL if none could be found
813 * (e.g. point is on whitespace).
814 *
815 * The point must be specified in container
816 * coordinates, relative to the container
817 * origin (which might be invisible if the
818 * container viewport has been scrolled up).
819 *
820 * With fsExtent, specify what part of the
821 * record should be checked. See
822 * cnrhScrollToRecord for more.
823 *
824 * This is not terribly fast, because it
825 * will send at least one message for each
826 * record which is currently visible in the
827 * container.
828 *
829 * With fl, specify any or none of the following:
830 *
831 * -- FRFP_RIGHTSPLITWINDOW: test right split Details view
832 * instead of main cnr.
833 *
834 * -- FRFP_SCREENCOORDS: *pptl specifies the point to
835 * check in _screen_ coordinates, instead of
836 * container ccordinates.
837 *
838 *@@added V0.9.1 (99-11-29) [umoeller]
839 *@@changed V0.9.4 (2000-08-08) [umoeller]: fixed viewport/window confusion; now works after cnr resize
840 */
841
842PRECORDCORE cnrhFindRecordFromPoint(HWND hwndCnr,
843 PPOINTL pptl, // in: point to check for
844 PRECTL prclFoundRecord,
845 // out: if != NULL and record was
846 // found, this receives the record rectl
847 // (or subrectl, depending on fsExtent)
848 ULONG fsExtent,
849 // in: one or several of
850 // CMA_ICON, CMA_TEXT, CMA_TREEICON
851 ULONG fl)
852{
853 PRECORDCORE preccReturn = NULL;
854 RECTL rclViewport;
855 HAB habCnr = WinQueryAnchorBlock(hwndCnr);
856
857 POINTL ptlCheck;
858
859 // _Pmpf(("Entering cnrhFindRecordFromPoint"));
860
861 ptlCheck.x = pptl->x;
862 ptlCheck.y = pptl->y;
863
864 if (fl & FRFP_SCREENCOORDS)
865 {
866 // _Pmpf((" mapping screen %d/%d to cnr", ptlCheck.x, ptlCheck.y));
867 WinMapWindowPoints(HWND_DESKTOP,
868 hwndCnr,
869 &ptlCheck,
870 1);
871 // _Pmpf((" got %d/%d", ptlCheck.x, ptlCheck.y));
872 }
873
874 // get cnr viewport (currently visible client area,
875 // relative to cnr origin)
876 if (WinSendMsg(hwndCnr,
877 CM_QUERYVIEWPORTRECT,
878 (MPARAM)&rclViewport,
879 MPFROM2SHORT(CMA_WINDOW, // CMA_WORKSPACE, V0.9.4 (2000-08-08) [umoeller]
880 ((fl & FRFP_RIGHTSPLITWINDOW) != 0))))
881 // right split window?
882 {
883 PRECORDCORE preccFound = (PRECORDCORE)CMA_FIRST;
884 QUERYRECFROMRECT qrfr;
885 QUERYRECORDRECT qrr;
886
887 // now enumerate all records which are visible in
888 // the viewport
889 do
890 {
891 qrfr.cb = sizeof(qrfr);
892 qrfr.rect.xLeft = rclViewport.xLeft;
893 qrfr.rect.yBottom = rclViewport.yBottom;
894 qrfr.rect.xRight = rclViewport.xRight;
895 qrfr.rect.yTop = rclViewport.yTop;
896 qrfr.fsSearch = CMA_PARTIAL | CMA_ITEMORDER;
897
898 // _Pmpf((" Enumerating recs in viewport %d, %d, %d, %d",
899 // rclViewport.xLeft, rclViewport.yBottom, rclViewport.xRight, rclViewport.yTop));
900
901 preccFound = (PRECORDCORE)WinSendMsg(hwndCnr,
902 CM_QUERYRECORDFROMRECT,
903 (MPARAM)preccFound, // CMA_FIRST on first loop
904 (MPARAM)&qrfr);
905 // _Pmpf((" CM_QUERYRECORDFROMRECT returned 0x%lX", preccFound));
906
907 if ( (preccFound != NULL)
908 && (preccFound != (PRECORDCORE)-1)
909 )
910 {
911 RECTL rclRecord;
912 qrr.cb = sizeof(qrr);
913 qrr.pRecord = preccFound;
914 qrr.fRightSplitWindow = ((fl & FRFP_RIGHTSPLITWINDOW) != 0);
915 qrr.fsExtent = fsExtent;
916 if (WinSendMsg(hwndCnr,
917 CM_QUERYRECORDRECT,
918 (MPARAM)&rclRecord,
919 (MPARAM)&qrr))
920 {
921 if (WinPtInRect(habCnr,
922 &rclRecord,
923 &ptlCheck))
924 {
925 // yes, it's in the record:
926 // return that
927 preccReturn = preccFound;
928
929 // if rectangle is queried,
930 // copy that
931 if (prclFoundRecord)
932 memcpy(prclFoundRecord, &rclRecord, sizeof(RECTL));
933 break;
934 }
935 }
936 }
937 else
938 // last one or error:
939 break;
940 } while (TRUE);
941 }
942 // else
943 // _Pmpf((" CM_QUERYVIEWPORTRECT failed."));
944
945 return (preccReturn);
946}
947
948/*
949 *@@ cnrhExpandFromRoot:
950 * expands prec and climbs up all parent
951 * records and expands them all as well.
952 *
953 * Returns the no. of records expanded.
954 *
955 *@@added V0.9.9 (2001-03-13) [umoeller]
956 */
957
958ULONG cnrhExpandFromRoot(HWND hwndCnr,
959 PRECORDCORE prec)
960{
961 ULONG ul = 0;
962 PRECORDCORE preccParent = prec;
963 while (preccParent)
964 {
965 WinSendMsg(hwndCnr, CM_EXPANDTREE, (MPARAM)preccParent, MPNULL);
966 ul++;
967
968 preccParent = (PRECORDCORE)WinSendMsg(hwndCnr,
969 CM_QUERYRECORD,
970 (MPARAM)preccParent,
971 MPFROM2SHORT(CMA_PARENT,
972 CMA_ITEMORDER));
973
974 if (preccParent == (PRECORDCORE)-1)
975 preccParent = NULL;
976 }
977
978 return (ul);
979}
980
981/*
982 *@@ cnrhScrollToRecord:
983 * scrolls a given container control to make a given
984 * record visible.
985 *
986 * Returns:
987 * -- 0: OK, scrolled
988 * -- 1: record rectangle query failed (error)
989 * -- 2: cnr viewport query failed (error)
990 * -- 3: record is already visible (scrolling not necessary)
991 * -- 4: cnrinfo query failed (error)
992 *
993 * Note: All messages are _sent_ to the container, not posted.
994 * Scrolling therefore occurs synchroneously before this
995 * function returns.
996 *
997 * This function an improved version of the one (W)(C) Dan Libby, found at
998 * http://zebra.asta.fh-weingarten.de/os2/Snippets/Howt6364.HTML
999 * Improvements (C) 1998 Ulrich M”ller.
1000 *
1001 *@@changed V0.9.4 (2000-08-07) [umoeller]: now posting scroll messages to avoid sync errors
1002 *@@changed V0.9.9 (2001-03-12) [umoeller]: this never scrolled for root records in tree view if KeepParent == TRUE, fixed
1003 *@@changed V0.9.9 (2001-03-13) [umoeller]: largely rewritten; this now scrolls x properly too and is faster
1004 */
1005
1006ULONG cnrhScrollToRecord(HWND hwndCnr, // in: container window
1007 PRECORDCORE pRec, // in: record to scroll to
1008 ULONG fsExtent,
1009 // in: this determines what parts of pRec
1010 // should be made visible. OR the following
1011 // flags:
1012 // -- CMA_ICON: the icon rectangle
1013 // -- CMA_TEXT: the record text
1014 // -- CMA_TREEICON: the "+" sign in tree view
1015 BOOL fKeepParent)
1016 // for tree views only: whether to keep
1017 // the parent record of pRec visible when scrolling.
1018 // If scrolling to pRec would make the parent
1019 // record invisible, we instead scroll so that
1020 // the parent record appears at the top of the
1021 // container workspace (Win95 style).
1022
1023{
1024 QUERYRECORDRECT qRect;
1025 RECTL rclRecord,
1026 rclCnr;
1027 LONG lXOfs = 0,
1028 lYOfs = 0;
1029
1030 qRect.cb = sizeof(qRect);
1031 qRect.pRecord = (PRECORDCORE)pRec;
1032 qRect.fsExtent = fsExtent;
1033
1034 if (fKeepParent)
1035 {
1036 CNRINFO CnrInfo;
1037 // this is only valid in tree view, so check
1038 if (!WinSendMsg(hwndCnr,
1039 CM_QUERYCNRINFO,
1040 (MPARAM)&CnrInfo,
1041 (MPARAM)sizeof(CnrInfo)))
1042 return 4;
1043 else
1044 // disable if not tree view
1045 fKeepParent = ((CnrInfo.flWindowAttr & CV_TREE) != 0);
1046 }
1047
1048 // query record location and size of container
1049 if (!WinSendMsg(hwndCnr,
1050 CM_QUERYRECORDRECT,
1051 &rclRecord,
1052 &qRect))
1053 return 1;
1054
1055 if (!WinSendMsg(hwndCnr,
1056 CM_QUERYVIEWPORTRECT,
1057 &rclCnr,
1058 MPFROM2SHORT(CMA_WINDOW,
1059 // returns the client area rectangle
1060 // in container window coordinates
1061 FALSE)) )
1062 return 2;
1063
1064 // check if left bottom point of pRec is currently visible in container
1065
1066 #define IS_BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c)))
1067
1068 // 1) set lXOfs if we need to scroll horizontally
1069 if (!IS_BETWEEN(rclRecord.xLeft, rclCnr.xLeft, rclCnr.xRight))
1070 // record xLeft is outside viewport:
1071 // scroll horizontally so that xLeft is exactly on left of viewport
1072 lXOfs = (rclRecord.xLeft - rclCnr.xLeft);
1073 else if (!IS_BETWEEN(rclRecord.xRight, rclCnr.xLeft, rclCnr.xRight))
1074 // record xRight is outside viewport:
1075 // scroll horizontally so that xRight is exactly on right of viewport
1076 lXOfs = (rclRecord.xRight - rclCnr.xRight);
1077
1078 // 2) set lYOfs if we need to scroll vertically
1079 if (!IS_BETWEEN(rclRecord.yBottom, rclCnr.yBottom, rclCnr.yTop))
1080 // record yBottom is outside viewport:
1081 // scroll horizontally so that yBottom is exactly on bottom of viewport
1082 lYOfs = (rclCnr.yBottom - rclRecord.yBottom) // this would suffice
1083 + (rclRecord.yTop - rclRecord.yBottom);
1084 // but we make the next rcl visible too
1085 else if (!IS_BETWEEN(rclRecord.yTop, rclCnr.yBottom, rclCnr.yTop))
1086 // record yTop is outside viewport:
1087 // scroll horizontally so that yTop is exactly on top of viewport
1088 lYOfs = (rclRecord.yTop - rclCnr.yTop);
1089
1090 if (fKeepParent && (lXOfs || lYOfs))
1091 {
1092 // keep parent enabled, and we're scrolling:
1093 // find the parent record then
1094 qRect.cb = sizeof(qRect);
1095 qRect.pRecord = (PRECORDCORE)WinSendMsg(hwndCnr,
1096 CM_QUERYRECORD,
1097 (MPARAM)pRec,
1098 MPFROM2SHORT(CMA_PARENT,
1099 CMA_ITEMORDER));
1100 if (qRect.pRecord) // V0.9.9 (2001-03-12) [umoeller]
1101 {
1102 // parent exists:
1103 // get PARENT record rectangle then
1104 RECTL rclParentRecord;
1105 qRect.fsExtent = fsExtent;
1106 if (WinSendMsg(hwndCnr,
1107 CM_QUERYRECORDRECT,
1108 &rclParentRecord,
1109 &qRect))
1110 {
1111 // check if parent record WOULD still be visible
1112 // if we scrolled what we calculated above
1113 RECTL rclCnr2;
1114 memcpy(&rclCnr2, &rclCnr, sizeof(rclCnr2));
1115 winhOffsetRect(&rclCnr2, lXOfs, -lYOfs);
1116
1117 if ( lXOfs
1118 && (!IS_BETWEEN(rclParentRecord.xLeft, rclCnr2.xLeft, rclCnr2.xRight))
1119 )
1120 // record xLeft is outside viewport:
1121 // scroll horizontally so that xLeft is exactly on left of viewport
1122 lXOfs = (rclParentRecord.xLeft - rclCnr.xLeft);
1123
1124 if ( lYOfs
1125 && (!IS_BETWEEN(rclParentRecord.yBottom, rclCnr2.yBottom, rclCnr2.yTop))
1126 )
1127 // record yBottom is outside viewport:
1128 // recalculate y ofs so that we scroll so
1129 // that parent record is on top of cnr viewport
1130 lYOfs = (rclCnr.yTop - rclParentRecord.yTop) // this would suffice
1131 - (rclRecord.yTop - rclRecord.yBottom); // but we make the previous rcl visible too
1132 }
1133 }
1134 }
1135
1136 if (lXOfs)
1137 // scroll horizontally
1138 WinPostMsg(hwndCnr,
1139 CM_SCROLLWINDOW,
1140 (MPARAM)CMA_HORIZONTAL,
1141 (MPARAM)lXOfs);
1142
1143 // scroll vertically
1144 if (lYOfs)
1145 WinPostMsg(hwndCnr,
1146 CM_SCROLLWINDOW,
1147 (MPARAM)CMA_VERTICAL,
1148 (MPARAM)lYOfs);
1149
1150 return 0;
1151}
1152
1153/*
1154 *@@ cnrhShowContextMenu:
1155 * this function shows the given menu as a context
1156 * menu for the given record core (using WinPopupMenu).
1157 * This function may be used when receiving WM_CONTROL
1158 * with CN_CONTEXTMENU from the container, which has
1159 * the preccSource in mp2.
1160 *
1161 * In detail, this function does the following:
1162 *
1163 * 1) query the coordinates where to show the menu;
1164 * if (preccSource), this will be next to the
1165 * record core, otherwise (i.e. menu requested
1166 * for whitespace) the mouse coordinates over
1167 * the container;
1168 *
1169 * 2) give preccSource (or, if NULL, the whole
1170 * container) source emphasis;
1171 *
1172 * 3) call WinPopupMenu.
1173 *
1174 * Note: It is the responsibility of the caller to catch
1175 * WM_MENUEND in the window procedure of hwndMenuOwner later
1176 * to remove the source emphasis for preccSource again.
1177 *
1178 * This function returns FALSE if an error occured.
1179 *
1180 *@@added V0.9.0 [umoeller]
1181 */
1182
1183BOOL cnrhShowContextMenu(HWND hwndCnr,
1184 PRECORDCORE preccSource, // in: mp2 of CN_CONTEXTMENU
1185 HWND hMenu, // in: menu to show
1186 HWND hwndMenuOwner) // in: menu owner (where the
1187 // WM_COMMAND will go to)
1188{
1189 BOOL brc = FALSE;
1190 if (hMenu)
1191 {
1192 BOOL fQueried = FALSE;
1193
1194 POINTL ptl;
1195 if (preccSource)
1196 {
1197 CNRINFO CnrInfo;
1198 cnrhQueryCnrInfo(hwndCnr, &CnrInfo);
1199
1200 if ((CnrInfo.flWindowAttr & CV_DETAIL) == 0)
1201 {
1202 // if we're not in Details view:
1203 // calculate the point where to show the context
1204 // menu; we use the lower-right corner of the
1205 // source record core
1206 QUERYRECORDRECT qRect;
1207 RECTL rclRecc;
1208 qRect.cb = sizeof(qRect);
1209 qRect.pRecord = preccSource;
1210 qRect.fsExtent = CMA_TEXT;
1211 WinSendMsg(hwndCnr,
1212 CM_QUERYRECORDRECT,
1213 &rclRecc,
1214 &qRect);
1215 ptl.x = rclRecc.xRight;
1216 ptl.y = rclRecc.yBottom;
1217 // now we have the lower-right corner in cnr coords
1218
1219 // clip if this is outside the container window
1220 WinQueryWindowRect(hwndCnr, &rclRecc);
1221 if (ptl.x > rclRecc.xRight)
1222 ptl.x = rclRecc.xRight;
1223 if (ptl.y > rclRecc.yTop)
1224 ptl.y = rclRecc.yTop;
1225
1226 // convert this to screen coordinates
1227 WinMapWindowPoints(hwndCnr,
1228 HWND_DESKTOP,
1229 &ptl,
1230 1);
1231 fQueried = TRUE;
1232 }
1233 }
1234
1235 if (!fQueried)
1236 // else: use mouse coordinates for context menu
1237 WinQueryPointerPos(HWND_DESKTOP, &ptl);
1238
1239 // give preccSource source emphasis;
1240 // if preccSource == NULL, the whole container will be
1241 // given source emphasis
1242 WinSendMsg(hwndCnr,
1243 CM_SETRECORDEMPHASIS,
1244 (MPARAM)preccSource, // might be NULL for whole container
1245 MPFROM2SHORT(TRUE, // set emphasis
1246 CRA_SOURCE));
1247
1248 // finally, show context menu
1249 brc = WinPopupMenu(HWND_DESKTOP, // menu parent
1250 hwndMenuOwner, // menu owner
1251 hMenu,
1252 (SHORT)ptl.x,
1253 (SHORT)ptl.y,
1254 0, // ID
1255 PU_NONE
1256 | PU_MOUSEBUTTON1
1257 | PU_KEYBOARD
1258 | PU_HCONSTRAIN
1259 | PU_VCONSTRAIN);
1260 }
1261
1262 return (brc);
1263}
1264
1265/*
1266 *@@ cnrhQuerySourceRecord:
1267 * this helper function evaluates a given container
1268 * to find out which records have been selected while
1269 * a context menu is open.
1270 *
1271 * This is for implementing a WPS-like (probably CUA) behavior
1272 * when invoking actions on container records. That is:
1273 *
1274 * 1) If the user opens a context menu on a selected object,
1275 * the selected action should be invoked on _all_ selected
1276 * objects.
1277 *
1278 * 2) If the user opens a context menu on an object which is
1279 * _not_ selected, the action should be invoked on that
1280 * object only (which should be given source emphasis),
1281 * no matter what other objects are selected.
1282 *
1283 * This function expects in preccSource the record core which
1284 * currently has (or just had) source emphasis.
1285 *
1286 * 1) In your own programs, you should have used cnrhShowContextMenu
1287 * above, which sets record source emphasis correctly. Unfortunately,
1288 * PM posts WM_MENUEND _before_ WM_COMMAND, so if you remove source
1289 * emphasis in WM_MENUEND, it is unknown which record was selected at
1290 * the time WM_COMMAND comes in... so you need to store that record
1291 * and pass it to this function later. Sorry.
1292 *
1293 * 2) With the WPS, this function works within the wpMenuItemSelected
1294 * method, because that one is invoked during the processing of
1295 * WM_COMMAND and the WPS automatically does the source emphasis
1296 * stuff right.
1297 *
1298 * The result of this evaluation is stored in *pulSelection,
1299 * which can be:
1300 *
1301 * -- SEL_WHITESPACE (1): the context menu was opened on the
1302 * whitespace of the container (preccSource
1303 * is NULL);
1304 * this func then returns NULL also.
1305 * -- SEL_SINGLESEL (2): the context menu was opened for a
1306 * single selected object:
1307 * this func then returns that record core
1308 * (which is preccSource).
1309 * -- SEL_MULTISEL (3): the context menu was opened on one
1310 * of a multitude of selected record;
1311 * this func then returns the first of the
1312 * selected records. Use
1313 * cnrhQueryNextSelectedRecord to get the others.
1314 * -- SEL_SINGLEOTHER (4): the context menu was opened for a
1315 * single record _other_ than the selected
1316 * records:
1317 * this func then returns that record
1318 * (which is preccSource).
1319 *
1320 *@@added V0.9.0 [umoeller]
1321 */
1322
1323PRECORDCORE cnrhQuerySourceRecord(HWND hwndCnr, // in: cnr
1324 PRECORDCORE preccSource, // in: record which had source emphasis
1325 PULONG pulSelection) // out: selection flags
1326{
1327 PRECORDCORE preccReturn = NULL;
1328
1329 if (preccSource == NULL)
1330 {
1331 // this probably means that the whole container has
1332 // source emphasis --> context menu on folder whitespace
1333 *pulSelection = SEL_WHITESPACE;
1334 // and return NULL
1335 }
1336 else if (((LONG)preccSource) != -1) // no error?
1337 {
1338 // check whether the source record is also selected
1339 if ((preccSource->flRecordAttr & CRA_SELECTED) == 0)
1340 {
1341 // no:
1342 // only one object, but not one of the selected ones
1343 // (if any at all)
1344 preccReturn = preccSource;
1345 *pulSelection = SEL_SINGLEOTHER;
1346 }
1347 else
1348 {
1349 // yes, source record _is_ selected:
1350 // check whether we have more than one selected record?
1351
1352 // get first selected record
1353 PRECORDCORE preccSelected = (PRECORDCORE)WinSendMsg(hwndCnr,
1354 CM_QUERYRECORDEMPHASIS,
1355 (MPARAM)CMA_FIRST,
1356 (MPARAM)CRA_SELECTED);
1357 // return that one
1358 preccReturn = preccSelected;
1359
1360 // are several objects selected?
1361 preccSelected = (PRECORDCORE)WinSendMsg(hwndCnr,
1362 CM_QUERYRECORDEMPHASIS,
1363 (MPARAM)preccSelected,
1364 // get next selected
1365 (MPARAM)CRA_SELECTED);
1366 if (preccSelected)
1367 // several objects
1368 *pulSelection = SEL_MULTISEL;
1369 else
1370 // only one object
1371 *pulSelection = SEL_SINGLESEL;
1372 }
1373 }
1374
1375 return (preccReturn);
1376}
1377
1378/*
1379 *@@ cnrhQueryNextSelectedRecord:
1380 * if cnrhQuerySourceRecord above returns SEL_MULTISEL
1381 * you can use this helper func to loop thru all the
1382 * selected records. This will return the next record
1383 * after preccCurrent which is selected or NULL if it's the last.
1384 *
1385 * If you're not using cnrhQuerySourceRecord (because your
1386 * records do not have source emphasis), you can also call
1387 * this function with (preccCurrent == CMA_FIRST) to get the
1388 * first selected record core.
1389 */
1390
1391PRECORDCORE cnrhQueryNextSelectedRecord(HWND hwndCnr,
1392 PRECORDCORE preccCurrent)
1393{
1394 PRECORDCORE preccReturn = 0;
1395 if (preccCurrent)
1396 {
1397 PRECORDCORE preccNext = (PRECORDCORE)WinSendMsg(hwndCnr,
1398 CM_QUERYRECORDEMPHASIS,
1399 (MPARAM)preccCurrent,
1400 (MPARAM)CRA_SELECTED);
1401 if ((preccNext) && ((LONG)preccNext != -1) )
1402 preccReturn = preccNext;
1403 }
1404 return (preccReturn);
1405}
1406
1407/*
1408 *@@category: Helpers\PM helpers\Container helpers\Record relations/iteration
1409 * functions for querying the relation of records and
1410 * iterating through records.
1411 */
1412
1413/* ******************************************************************
1414 *
1415 * Record relations/iteration
1416 *
1417 ********************************************************************/
1418
1419/*
1420 *@@ cnrhQueryRecordIndex:
1421 * returns the "index" of the specified record
1422 * in the specified container. That is, if the
1423 * specified record is the first record in the
1424 * container, 0 is returned. If it's the second,
1425 * 1 is returned, and so on.
1426 *
1427 * Returns -1 if precc could not be found.
1428 *
1429 * Doesn't work in Tree view.
1430 *
1431 *@@added V0.9.3 (2000-04-19) [umoeller]
1432 */
1433
1434LONG cnrhQueryRecordIndex(HWND hwndCnr,
1435 PRECORDCORE precc)
1436{
1437 PRECORDCORE precc2 = (PRECORDCORE)CMA_FIRST;
1438 BOOL fFirstCall = TRUE;
1439 LONG lrc = -1,
1440 lCount = 0;
1441
1442 while (TRUE)
1443 {
1444 precc2 =
1445 (PRECORDCORE)WinSendMsg(hwndCnr,
1446 CM_QUERYRECORD,
1447 (MPARAM)precc2, // ignored on first call
1448 MPFROM2SHORT(
1449 (fFirstCall)
1450 ? CMA_FIRST
1451 : CMA_NEXT,
1452 CMA_ITEMORDER)
1453 );
1454 if ( (precc2 == NULL)
1455 || (precc2 == (PRECORDCORE)-1)
1456 )
1457 // error:
1458 // return -1
1459 break;
1460 else
1461 if (precc2 == precc)
1462 {
1463 // same as search record:
1464 lrc = lCount;
1465 break;
1466 }
1467
1468 // else search on
1469 fFirstCall = FALSE;
1470 lCount++;
1471 }
1472
1473 return (lrc);
1474}
1475
1476/*
1477 *@@ cnrhIsChildOf:
1478 * returns TRUE only if precTest is a child record
1479 * of precParent in a tree view.
1480 *
1481 *@@added V0.9.7 (2000-12-13) [umoeller]
1482 */
1483
1484BOOL cnrhIsChildOf(HWND hwndCnr,
1485 PRECORDCORE precTest, // in: recc to test
1486 PRECORDCORE precParent) // in: parent to test
1487{
1488 BOOL brc = FALSE;
1489 if ((precTest) && (precParent))
1490 {
1491 PRECORDCORE precParentThis = precTest;
1492
1493 while (precParentThis)
1494 {
1495 // first call: get parent of precTest;
1496 // subsequent calls: climb up
1497 precParentThis = (PRECORDCORE)WinSendMsg(hwndCnr,
1498 CM_QUERYRECORD,
1499 precParentThis,
1500 MPFROM2SHORT(CMA_PARENT,
1501 CMA_ITEMORDER));
1502 if (precParentThis == (PRECORDCORE)-1)
1503 break;
1504 else
1505 if (precParentThis == precParent)
1506 {
1507 brc = TRUE;
1508 break;
1509 }
1510 }
1511 }
1512
1513 return (brc);
1514}
1515
1516/*
1517 *@@ cnrhForAllRecords:
1518 * this monster function calls pfnwpCallback
1519 * for really all the records in the container,
1520 * including child records in tree view.
1521 *
1522 * This is extremely useful for cleaning up
1523 * all record cores before a container window
1524 * gets destroyed.
1525 *
1526 * This function recurses for child records.
1527 * On the first call, preccParent should be
1528 * NULL; you may however specify a certain
1529 * record, and this function will call the
1530 * callback only for that record and children.
1531 *
1532 * pfnwpCallback gets called with the following
1533 * parameters:
1534 *
1535 * -- HWND hwnd: hwndCnr, as passed to this func
1536 * -- PRECORDCORE precc: current record core, as
1537 * determined by this func.
1538 * -- ULONG ulUser1/2: what you have specified here.
1539 *
1540 * It must be declared as follows:
1541 *
1542 + ULONG EXPENTRY fncb(HWND hwndCnr,
1543 + PRECORDCORE precc,
1544 + ULONG ulUser1,
1545 + ULONG ulUser2)
1546 *
1547 * If the callback returns anything != 0, this
1548 * function stops even before all records have
1549 * been processed. You can use ulUser for a
1550 * pointer to a return value.
1551 *
1552 * This always returns the no. of records which
1553 * were processed.
1554 *
1555 * If you use this function for deleting record
1556 * cores, you can be sure that you can delete
1557 * every record, because your callback gets called
1558 * for the child records before the parent record.
1559 *
1560 *@@added V0.9.0 [umoeller]
1561 */
1562
1563ULONG cnrhForAllRecords(HWND hwndCnr,
1564 PRECORDCORE preccParent, // in: NULL for root
1565 PFNCBRECC pfncbRecc, // in: callback
1566 ULONG ulUser1,
1567 ULONG ulUser2)
1568{
1569 PRECORDCORE precc2 = preccParent;
1570 ULONG ulrc = 0;
1571 USHORT usQuery;
1572 BOOL fFirstCall = TRUE;
1573
1574 while (TRUE)
1575 {
1576 if (fFirstCall)
1577 {
1578 // first call:
1579 if (preccParent)
1580 // non-root:
1581 usQuery = CMA_FIRSTCHILD;
1582 else
1583 // NULL == root:
1584 usQuery = CMA_FIRST;
1585 }
1586 else
1587 // subsequent calls:
1588 usQuery = CMA_NEXT; // works as CMA_NEXTCHILD also
1589
1590 precc2 =
1591 (PRECORDCORE)WinSendMsg(hwndCnr,
1592 CM_QUERYRECORD,
1593 (MPARAM)((fFirstCall)
1594 // first call (CMA_FIRSTCHILD or CMA_FIRST):
1595 ? preccParent // ignored for CMA_FIRST
1596 // subsequent calls (CMA_NEXTCHILD or CMA_NEXT):
1597 : precc2), // what we queried last
1598 MPFROM2SHORT(
1599 usQuery, // set above
1600 CMA_ITEMORDER)
1601 );
1602
1603 if ((precc2) && ((ULONG)precc2 != -1))
1604 {
1605 // record found:
1606 // recurse for that record
1607 ulrc += cnrhForAllRecords(hwndCnr,
1608 precc2, // new parent to search
1609 pfncbRecc,
1610 ulUser1,
1611 ulUser2);
1612
1613 // _Pmpf(("Calling callback for %s", precc2->pszIcon));
1614
1615 // call callback
1616 if (pfncbRecc)
1617 if ((*pfncbRecc)(hwndCnr, precc2, ulUser1, ulUser2))
1618 // returns something != NULL:
1619 // stop
1620 break;
1621 ulrc++;
1622 }
1623 else
1624 // no more records or error: get outta here
1625 break;
1626
1627 fFirstCall = FALSE;
1628 }
1629
1630 return (ulrc);
1631}
1632
1633/*
1634 * cnrhForAllChildRecords:
1635 * calls the specified fncbRecc callback for
1636 * the specified recc and all its child records.
1637 *
1638 *@@added V0.9.0 [umoeller]
1639 */
1640
1641/* VOID cnrhForAllChildRecords(HWND hwndCnr,
1642 PRECORDCORE precc,
1643 PFNCBRECC pfncbRecc,
1644 ULONG ulp1,
1645 ULONG ulp2)
1646{
1647 PRECORDCORE precc2 = precc;
1648 (*pfncbRecc)(precc, ulp1, ulp2);
1649 do {
1650 precc2 =
1651 (PRECORDCORE)WinSendMsg(hwndCnr,
1652 CM_QUERYRECORD,
1653 (MPARAM)precc2,
1654 MPFROM2SHORT(
1655 (precc2 == precc)
1656 ? CMA_FIRSTCHILD : CMA_NEXT,
1657 CMA_ITEMORDER)
1658 );
1659 if ((LONG)precc2 == -1)
1660 precc2 = NULL;
1661 if (precc2)
1662 // recurse again
1663 cnrhForAllChildRecords(hwndCnr, precc2, pfncbRecc, ulp1, ulp2);
1664 } while (precc2);
1665} */
1666
1667/*
1668 * cnrhForAllRecords2:
1669 * this is a useful function which calls
1670 * the specified callback function for
1671 * really all records in the container of
1672 * the main window, including child records.
1673 *
1674 * xxx
1675 *
1676 *@@added V0.9.0 [umoeller]
1677 */
1678
1679/* VOID cnrhForAllRecords2(HWND hwndCnr,
1680 PFNCBRECC pfncbRecc,
1681 ULONG ulp1,
1682 ULONG ulp2)
1683{
1684 PRECORDCORE precc2 = NULL;
1685 do {
1686 precc2 =
1687 (PRECORDCORE)WinSendMsg(hwndCnr,
1688 CM_QUERYRECORD,
1689 (MPARAM)precc2,
1690 MPFROM2SHORT(
1691 ((precc2 == NULL) ? CMA_FIRST : CMA_NEXT),
1692 CMA_ITEMORDER)
1693 );
1694 if ((LONG)precc2 == -1)
1695 precc2 = NULL;
1696 if (precc2)
1697 // recurse again
1698 cnrhForAllChildRecords(hwndCnr, precc2, pfncbRecc, ulp1, ulp2);
1699 } while (precc2);
1700} */
1701
1702/*
1703 * cnrhForAllParentRecords:
1704 * just as above, but climbs up instead.
1705 * The first call of the callback will be
1706 * for the parent record of precc.
1707 *
1708 *@@added V0.9.0 [umoeller]
1709 */
1710
1711/* VOID cnrhForAllParentRecords(HWND hwndCnr,
1712 PRECORDCORE precc,
1713 PFNCBRECC pfncbRecc,
1714 ULONG ulp1,
1715 ULONG ulp2)
1716{
1717 PRECORDCORE precc2 = precc;
1718 do {
1719 precc2 =
1720 (PRECORDCORE)WinSendMsg(hwndCnr,
1721 CM_QUERYRECORD,
1722 (MPARAM)precc2,
1723 MPFROM2SHORT(CMA_PARENT,
1724 CMA_ITEMORDER)
1725 );
1726 if ((LONG)precc2 == -1)
1727 precc2 = NULL;
1728 if (precc2)
1729 (*pfncbRecc)(precc2, ulp1, ulp2);
1730 } while (precc2);
1731} */
1732
1733/*
1734 *@@category: Helpers\PM helpers\Container helpers\Miscellaneous
1735 */
1736
1737/* ******************************************************************
1738 *
1739 * Miscellaneous
1740 *
1741 ********************************************************************/
1742
1743/*
1744 *@@ cnrhQueryCnrFromFrame:
1745 * find the handle of a frame window's container; we do this
1746 * by enumerating all the frame's child windows and comparing
1747 * their window classes to the WC_CONTAINER code.
1748 * This is not terribly fast, so use this func economically.
1749 * Returns NULLHANDLE if not found.
1750 */
1751
1752HWND cnrhQueryCnrFromFrame(HWND hwndFrame)
1753{
1754 HENUM henum;
1755 CHAR szClassName[256];
1756 HWND hwndCnr = NULLHANDLE,
1757 hwndTemp = NULLHANDLE;
1758
1759 if (hwndFrame)
1760 {
1761 henum = WinBeginEnumWindows(hwndFrame);
1762 if (henum)
1763 {
1764 do
1765 {
1766 hwndTemp = WinGetNextWindow(henum);
1767 if (hwndTemp)
1768 {
1769 if (WinQueryClassName(hwndTemp, 250, szClassName))
1770 if (strcmp(szClassName, "#37") == 0)
1771 // unbelievable, this is PM's code for WC_CONTAINER...
1772 hwndCnr = hwndTemp;
1773 }
1774 } while (hwndTemp);
1775 }
1776 WinEndEnumWindows(henum);
1777 }
1778
1779 return hwndCnr;
1780}
1781
1782/*
1783 *@@ cnrhInitDrag:
1784 * this sets up the necessary structures to begin dragging
1785 * a record core from a container. This helper func should be
1786 * called if your container should support being the source
1787 * window of a direct manipulation.
1788 *
1789 * This should get called in three situations:
1790 *
1791 * -- the container sends CN_INITDRAG ("real" d'n'd desired by user);
1792 *
1793 * -- the container sends us CN_PICKUP (Alt+MB2 pressed);
1794 *
1795 * -- the user has selected "Pickup" from a record core's
1796 * context menu (ID_XSMI_FILETYPES_PICKUP command).
1797 * In that case, you can also call this function with
1798 * usNotifyCode == CN_PICKUP.
1799 *
1800 * In all three cases, preccDrag must be the record core
1801 * which is to be dragged.
1802 *
1803 * Depending on usNotifyCode, this function, after having allocated
1804 * the necessary data, will do the following:
1805 *
1806 * 1) If (usNotifyCode == CN_PICKUP), we will initiate a non-modal
1807 * (lazy) drag (DrgLazyDrag). This function will then return
1808 * after the records have been given "picked" emphasis.
1809 *
1810 * Note: You must intercept CN_DROPNOTIFY in your window proc
1811 * to clean up resources later. For this, call:
1812 *
1813 + DrgDeleteDraginfoStrHandles(pdrgInfo);
1814 + DrgFreeDraginfo(pdrgInfo);
1815 *
1816 * 2) However, if (usNotifyCode == CN_INITDRAG), we will start
1817 * a regular modal drag here by calling DrgDrag. This function
1818 * will _not_ return until the object has been dropped or d'n'd
1819 * has been cancelled. PM establishes another message loop
1820 * internally for this. In this case, this function managed
1821 * cleanup automatically.
1822 *
1823 * This function supports one single record core only. The following
1824 * information will be set in the DRAGITEM structure:
1825 *
1826 * -- ulItemID will be set to the preccDrag so that the target
1827 * window can access the dragged record.
1828 *
1829 * -- hstrSourceName == hstrTargetName gets the RECORDCORE.pszIcon.
1830 *
1831 * The drag icon will be a default system file icon.
1832 *
1833 * Preconditions:
1834 *
1835 * -- pszIcon must be set in the RECORDCORE. This is used for
1836 * the item source name. This must not be NULL.
1837 */
1838
1839PDRAGINFO cnrhInitDrag(HWND hwndCnr,
1840 // in: source container window
1841 PRECORDCORE preccDrag,
1842 // in: record to be dragged (only one supported)
1843 USHORT usNotifyCode,
1844 // in: CN_INITDRAG or CN_PICKUP
1845 PSZ pszRMF,
1846 // in: rendering mechanism and format,
1847 // e.g. "(DRM_MYFILETYPE)x(DRF_UNKNOWN)"
1848 USHORT usSupportedOps)
1849 // stored in DRAGITEM.fsSupportedOps,
1850 // one or several of DO_COPYABLE, DO_MOVEABLE, DO_LINKABLE
1851{
1852 DRAGIMAGE drgImage;
1853 PDRAGINFO pdrgInfo = NULL;
1854
1855 memset(&drgImage, 0, sizeof(drgImage));
1856 pdrgInfo = DrgAllocDraginfo(1); // one item only
1857 if (pdrgInfo)
1858 {
1859 DRAGITEM drgItem;
1860 memset(&drgItem, 0, sizeof(drgItem));
1861
1862 drgItem.hwndItem = hwndCnr;
1863 drgItem.ulItemID = (ULONG)preccDrag;
1864 // we use this to store the container rec
1865 drgItem.hstrType = DrgAddStrHandle(DRT_UNKNOWN);
1866 // application defined
1867 drgItem.hstrRMF = DrgAddStrHandle(pszRMF);
1868 drgItem.hstrContainerName = 0;
1869 drgItem.hstrSourceName = DrgAddStrHandle(preccDrag->pszIcon);
1870 drgItem.hstrTargetName = drgItem.hstrSourceName;
1871 drgItem.fsSupportedOps = usSupportedOps;
1872
1873 // set the DRAGITEM struct into the memory
1874 // allocated by DrgAllocDraginfo()
1875 DrgSetDragitem(pdrgInfo,
1876 &drgItem,
1877 sizeof(DRAGITEM),
1878 0); // item index
1879
1880 // fill in the DRAGIMAGE structure
1881 drgImage.cb = sizeof(DRAGIMAGE);
1882 drgImage.hImage = WinQuerySysPointer(HWND_DESKTOP,
1883 SPTR_FILE,
1884 FALSE);
1885 // pointer used for dragging; we
1886 // use a dull default file icon
1887 drgImage.fl = DRG_ICON; // hImage is an HPOINTER
1888 drgImage.cxOffset = 0; // 5 * iOffset; // Image offset from mouse pointer
1889 drgImage.cyOffset = 0; // 5 * iOffset; // Image offset from mouse pointer
1890
1891 // set source emphasis for the container record
1892 WinSendMsg(hwndCnr,
1893 CM_SETRECORDEMPHASIS,
1894 (MPARAM)preccDrag,
1895 MPFROM2SHORT(TRUE,
1896 (usNotifyCode == CN_INITDRAG)
1897 // for dragging: source emphasis
1898 ? CRA_SOURCE
1899 // for lazy drag: picked emphasis
1900 : CRA_PICKED));
1901
1902 if (usNotifyCode == CN_INITDRAG)
1903 {
1904 // "real" dragging:
1905 // call modal function for drag'n'drop.
1906 // This does not return until either
1907 // d'n'd has been cancelled or the
1908 // record core has been dropped.
1909 /* HWND hwndTarget = */ DrgDrag(hwndCnr,
1910 pdrgInfo,
1911 &drgImage,
1912 1, // drag image count
1913 VK_ENDDRAG, // system drag button
1914 NULL); // reserved
1915
1916 // since it's the source which is responsible
1917 // for cleaning up the resources, this is
1918 // what we do now (we had a modal d'n'd)
1919 DrgDeleteDraginfoStrHandles(pdrgInfo);
1920 DrgFreeDraginfo(pdrgInfo);
1921
1922 // remove source emphasis for the container record
1923 WinSendMsg(hwndCnr,
1924 CM_SETRECORDEMPHASIS,
1925 (MPARAM)preccDrag,
1926 MPFROM2SHORT(FALSE,
1927 CRA_SOURCE));
1928 } // end if (usNotifyCode == CN_INITDRAG)
1929 else
1930 {
1931 // "lazy drag" (CN_PICKUP):
1932 // initiate lazy drag. This function returns
1933 // immediately, since lazy drag is non-modal.
1934 // As a result, we cannot clean up the resources
1935 // here, but need to do this later (CN_DROPNOTIFY).
1936 DrgLazyDrag(hwndCnr,
1937 pdrgInfo,
1938 &drgImage,
1939 1, // drag image count
1940 0); // reserved
1941 }
1942 } // end if (pdrgInfo)
1943
1944 return (pdrgInfo);
1945}
1946
1947/*
1948 *@@ cnrhOwnerDrawRecord:
1949 * this helper func can be called upon receiving
1950 * WM_DRAWITEM for owner-drawing container record
1951 * cores.
1952 *
1953 * Presently, this function supports drawing record
1954 * cores in gray color if the record has the CRA_DISABLED
1955 * style (which, AFAIK, PM ignores per default).
1956 *
1957 * This returns either TRUE or FALSE as an MPARAM, depending
1958 * on whether we have drawn the item. This return value should
1959 * also be the return value of your window procedure.
1960 */
1961
1962MRESULT cnrhOwnerDrawRecord(MPARAM mp2) // in: mp2 of WM_DRAWITEM (POWNERITEM)
1963{
1964 MRESULT mrc = 0;
1965
1966 // get generic DRAWITEM structure
1967 POWNERITEM poi = (POWNERITEM)mp2;
1968
1969 // check if we're to draw the text
1970 // (and not the icon)
1971 if (poi->idItem == CMA_TEXT)
1972 {
1973 // get container-specific draw-item struct
1974 PCNRDRAWITEMINFO pcdii = (PCNRDRAWITEMINFO)poi->hItem;
1975
1976 if (((pcdii->pRecord->flRecordAttr) & CRA_DISABLED) == 0)
1977 {
1978 /*
1979 // not disabled == valid WPS class
1980 if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
1981 {
1982 // not disabled, but selected:
1983 lBackground = winhQueryPresColor(hwndDlg, PP_HILITEBACKGROUNDCOLOR, SYSCLR_HILITEBACKGROUND);
1984 lForeground = winhQueryPresColor(hwndDlg, PP_HILITEFOREGROUNDCOLOR, SYSCLR_HILITEFOREGROUND);
1985 }
1986 else
1987 {
1988 // not disabled, not selected:
1989 lBackground = winhQueryPresColor(hwndDlg, PP_BACKGROUNDCOLOR, SYSCLR_BACKGROUND);
1990 lForeground = winhQueryPresColor(hwndDlg, PP_FOREGROUNDCOLOR, SYSCLR_WINDOWTEXT);
1991 } */
1992 mrc = FALSE;
1993 // let cnr draw the thing
1994 }
1995 else
1996 {
1997 // CRA_DISABLED:
1998
1999 ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT;
2000 RECTL rcl2;
2001
2002 // set draw colors
2003 LONG lBackground,
2004 lForeground;
2005
2006 // switch to RGB
2007 GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL);
2008
2009 if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
2010 {
2011 // disabled and selected:
2012 lBackground = WinQuerySysColor(HWND_DESKTOP,
2013 SYSCLR_SHADOWTEXT, 0);
2014 lForeground = winhQueryPresColor(poi->hwnd,
2015 PP_BACKGROUNDCOLOR,
2016 FALSE, // no inherit
2017 SYSCLR_WINDOW);
2018 }
2019 else
2020 {
2021 // disabled and not selected:
2022 lBackground = winhQueryPresColor(poi->hwnd,
2023 PP_BACKGROUNDCOLOR,
2024 FALSE,
2025 SYSCLR_WINDOW);
2026 lForeground = WinQuerySysColor(HWND_DESKTOP,
2027 SYSCLR_SHADOWTEXT, 0);
2028 }
2029
2030 memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2));
2031 /* WinDrawText(poi->hps,
2032 strlen(pcdii->pRecord->pszText),
2033 pcdii->pRecord->pszText,
2034 &rcl2,
2035 lForeground, // foreground
2036 lBackground,
2037 flCmd); */
2038
2039 GpiSetBackColor(poi->hps, lBackground);
2040 GpiSetColor(poi->hps, lForeground);
2041
2042 winhDrawFormattedText(poi->hps,
2043 &rcl2,
2044 pcdii->pRecord->pszText,
2045 flCmd);
2046
2047 mrc = (MPARAM)TRUE; // tell cnr that we've drawn the item
2048 }
2049 } else
2050 mrc = (MPARAM)FALSE; // tell cnr to draw the item
2051
2052 return (mrc);
2053}
2054
2055/*
2056 *@@ cnrhDateTimeDos2Win:
2057 * this converts the information in a Control Program
2058 * DATETIME structure (as returned by DosGetDateTime)
2059 * to the CDATE and CTIME structures used by containers.
2060 *
2061 * If any of the target pointers is NULL, that data is
2062 * not converted.
2063 */
2064
2065BOOL cnrhDateTimeDos2Win(DATETIME* pdt, // in: Dos format date and time
2066 CDATE* pcdate, // out: container format date
2067 CTIME* pctime) // out: container format time
2068{
2069 if (pdt)
2070 {
2071 if (pcdate)
2072 {
2073 pcdate->day = pdt->day;
2074 pcdate->month = pdt->month;
2075 pcdate->year = pdt->year;
2076 }
2077 if (pctime)
2078 {
2079 pctime->seconds = pdt->seconds;
2080 pctime->minutes = pdt->minutes;
2081 pctime->hours = pdt->hours;
2082 }
2083 return (TRUE);
2084 }
2085 else
2086 return (FALSE);
2087}
2088
2089/*
2090 *@@ cnrhDateDos2Win:
2091 * converts an FDATE structure (Control program)
2092 * to a container CDATE structure.
2093 */
2094
2095BOOL cnrhDateDos2Win(FDATE* pfd, // in: DOS date
2096 CDATE* pcd) // out: container date
2097{
2098 if ((pfd) && (pcd))
2099 {
2100 pcd->day = pfd->day;
2101 pcd->month = pfd->month;
2102 pcd->year = pfd->year + 1980;
2103 return (TRUE);
2104 }
2105 else
2106 return (FALSE);
2107}
2108
2109/*
2110 *@@ cnrhTimeDos2Win:
2111 * converts an FTIME structure (Control program)
2112 * to a container CTIME structure.
2113 */
2114
2115BOOL cnrhTimeDos2Win(FTIME* pft, // in: DOS time
2116 CTIME* pct) // out: container time
2117{
2118 if ((pft) && (pct))
2119 {
2120 pct->seconds = pft->twosecs * 2;
2121 pct->minutes = pft->minutes;
2122 pct->hours = pft->hours;
2123 pct->ucReserved = 0;
2124 return (TRUE);
2125 }
2126 else
2127 return (FALSE);
2128}
Note: See TracBrowser for help on using the repository browser.