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

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

Misc. updates.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 75.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 PSZ pszText,
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 (pszText) // V0.9.0
487 {
488 precc->pszIcon = pszText;
489 precc->pszText = pszText;
490 precc->pszName = pszText;
491 precc->pszTree = pszText;
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 anyways.
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 *@@ cnrhScrollToRecord:
950 * scrolls a given container control to make a given
951 * record visible.
952 *
953 * Returns:
954 * -- 0: OK, scrolled
955 * -- 1: record rectangle query failed (error)
956 * -- 2: cnr viewport query failed (error)
957 * -- 3: record is already visible (scrolling not necessary)
958 * -- 4: cnrinfo query failed (error)
959 * -- 5: parent record rectangle query failed (error)
960 *
961 * Note: All messages are _sent_ to the container, not posted.
962 * Scrolling therefore occurs synchroneously before this
963 * function returns.
964 *
965 * This function an improved version of the one (W)(C) Dan Libby, found at
966 * http://zebra.asta.fh-weingarten.de/os2/Snippets/Howt6364.HTML
967 * Improvements (C) 1998 Ulrich M”ller.
968 *
969 *@@changed V0.9.4 (2000-08-07) [umoeller]: now posting scroll messages to avoid sync errors
970 */
971
972ULONG cnrhScrollToRecord(HWND hwndCnr, // in: container window
973 PRECORDCORE pRec, // in: record to scroll to
974 ULONG fsExtent,
975 // in: this determines what parts of pRec
976 // should be made visible. OR the following
977 // flags:
978 // -- CMA_ICON: the icon rectangle
979 // -- CMA_TEXT: the record text
980 // -- CMA_TREEICON: the "+" sign in tree view
981 BOOL KeepParent)
982 // for tree views only: whether to keep
983 // the parent record of pRec visible when scrolling.
984 // If scrolling to pRec would make the parent
985 // record invisible, we instead scroll so that
986 // the parent record appears at the top of the
987 // container workspace (Win95 style).
988
989{
990 QUERYRECORDRECT qRect, qRect2;
991 RECTL rclRecord, rclParentRecord, rclCnr, rclCnr2;
992 POINTL ptlRecord, ptlParentRecord;
993 CNRINFO CnrInfo;
994 HAB hab = WinQueryAnchorBlock(hwndCnr);
995 BOOL KeepParent2;
996 LONG lYOfs;
997
998 qRect.cb = sizeof(qRect);
999 qRect.pRecord = (PRECORDCORE)pRec;
1000 qRect.fsExtent = fsExtent;
1001
1002 // query record location and size of container
1003 if (!WinSendMsg(hwndCnr, CM_QUERYRECORDRECT, &rclRecord, &qRect))
1004 return 1;
1005 if (!WinSendMsg(hwndCnr, CM_QUERYVIEWPORTRECT, &rclCnr, MPFROM2SHORT(CMA_WINDOW, FALSE)) )
1006 return 2;
1007
1008 // check if left bottom point of pRec is currently visible in container
1009 ptlRecord.x = (rclRecord.xLeft);
1010 ptlRecord.y = (rclRecord.yBottom);
1011 // ptlRecord.x = (rclRecord.xLeft + rclRecord.xRight) / 2;
1012 // ptlRecord.y = (rclRecord.yBottom + rclRecord.yTop) / 2;
1013 if (WinPtInRect(hab, &rclCnr, &ptlRecord))
1014 return 3;
1015
1016 if (KeepParent)
1017 {
1018 if (!WinSendMsg(hwndCnr, CM_QUERYCNRINFO, (MPARAM)&CnrInfo, (MPARAM)sizeof(CnrInfo)))
1019 return 4;
1020 else
1021 KeepParent2 = (CnrInfo.flWindowAttr & CV_TREE);
1022 }
1023 else
1024 KeepParent2 = FALSE;
1025
1026 // calculate offset to scroll to make pRec visible
1027 lYOfs = (rclCnr.yBottom - rclRecord.yBottom) // this would suffice
1028 + (rclRecord.yTop - rclRecord.yBottom); // but we make the next rcl visible too
1029
1030 if (KeepParent2)
1031 {
1032 qRect2.cb = sizeof(qRect2);
1033 qRect2.pRecord = (PRECORDCORE)WinSendMsg(hwndCnr,
1034 CM_QUERYRECORD,
1035 (MPARAM)pRec,
1036 MPFROM2SHORT(CMA_PARENT,
1037 CMA_ITEMORDER));
1038 qRect2.fsExtent = fsExtent;
1039
1040 // now query PARENT record location and size of container
1041 if (!WinSendMsg(hwndCnr, CM_QUERYRECORDRECT, &rclParentRecord, &qRect2))
1042 return 5;
1043
1044 ptlParentRecord.x = (rclParentRecord.xLeft);
1045 ptlParentRecord.y = (rclParentRecord.yTop);
1046 // ptlParentRecord.x = (rclParentRecord.xLeft + rclParentRecord.xRight) / 2;
1047 // ptlParentRecord.y = (rclParentRecord.yBottom + rclParentRecord.yTop) / 2;
1048 rclCnr2 = rclCnr;
1049 WinOffsetRect(hab, &rclCnr2, 0, -lYOfs);
1050 // if ( (rclParentRecord.yBottom - rclRecord.yBottom) > (rclCnr.yTop - rclCnr.yBottom) )
1051 if (!(WinPtInRect(hab, &rclCnr2, &ptlParentRecord)))
1052 {
1053 lYOfs = (rclCnr.yTop - rclParentRecord.yTop) // this would suffice
1054 - (rclRecord.yTop - rclRecord.yBottom); // but we make the previous rcl visible too
1055 }
1056 }
1057
1058 if (!KeepParent2)
1059 // scroll horizontally
1060 WinPostMsg(hwndCnr,
1061 CM_SCROLLWINDOW,
1062 (MPARAM)CMA_HORIZONTAL,
1063 (MPARAM)(rclRecord.xLeft - rclCnr.xLeft));
1064
1065 // scroll vertically
1066 WinPostMsg(hwndCnr,
1067 CM_SCROLLWINDOW,
1068 (MPARAM)CMA_VERTICAL,
1069 (MPARAM)lYOfs);
1070
1071 return 0;
1072}
1073
1074/*
1075 *@@ cnrhShowContextMenu:
1076 * this function shows the given menu as a context
1077 * menu for the given record core (using WinPopupMenu).
1078 * This function may be used when receiving WM_CONTROL
1079 * with CN_CONTEXTMENU from the container, which has
1080 * the preccSource in mp2.
1081 *
1082 * In detail, this function does the following:
1083 *
1084 * 1) query the coordinates where to show the menu;
1085 * if (preccSource), this will be next to the
1086 * record core, otherwise (i.e. menu requested
1087 * for whitespace) the mouse coordinates over
1088 * the container;
1089 *
1090 * 2) give preccSource (or, if NULL, the whole
1091 * container) source emphasis;
1092 *
1093 * 3) call WinPopupMenu.
1094 *
1095 * Note: It is the responsibility of the caller to catch
1096 * WM_MENUEND in the window procedure of hwndMenuOwner later
1097 * to remove the source emphasis for preccSource again.
1098 *
1099 * This function returns FALSE if an error occured.
1100 *
1101 *@@added V0.9.0 [umoeller]
1102 */
1103
1104BOOL cnrhShowContextMenu(HWND hwndCnr,
1105 PRECORDCORE preccSource, // in: mp2 of CN_CONTEXTMENU
1106 HWND hMenu, // in: menu to show
1107 HWND hwndMenuOwner) // in: menu owner (where the
1108 // WM_COMMAND will go to)
1109{
1110 BOOL brc = FALSE;
1111 if (hMenu)
1112 {
1113 BOOL fQueried = FALSE;
1114
1115 POINTL ptl;
1116 if (preccSource)
1117 {
1118 CNRINFO CnrInfo;
1119 cnrhQueryCnrInfo(hwndCnr, &CnrInfo);
1120
1121 if ((CnrInfo.flWindowAttr & CV_DETAIL) == 0)
1122 {
1123 // if we're not in Details view:
1124 // calculate the point where to show the context
1125 // menu; we use the lower-right corner of the
1126 // source record core
1127 QUERYRECORDRECT qRect;
1128 RECTL rclRecc;
1129 qRect.cb = sizeof(qRect);
1130 qRect.pRecord = preccSource;
1131 qRect.fsExtent = CMA_TEXT;
1132 WinSendMsg(hwndCnr,
1133 CM_QUERYRECORDRECT,
1134 &rclRecc,
1135 &qRect);
1136 ptl.x = rclRecc.xRight;
1137 ptl.y = rclRecc.yBottom;
1138 // now we have the lower-right corner in cnr coords
1139
1140 // clip if this is outside the container window
1141 WinQueryWindowRect(hwndCnr, &rclRecc);
1142 if (ptl.x > rclRecc.xRight)
1143 ptl.x = rclRecc.xRight;
1144 if (ptl.y > rclRecc.yTop)
1145 ptl.y = rclRecc.yTop;
1146
1147 // convert this to screen coordinates
1148 WinMapWindowPoints(hwndCnr,
1149 HWND_DESKTOP,
1150 &ptl,
1151 1);
1152 fQueried = TRUE;
1153 }
1154 }
1155
1156 if (!fQueried)
1157 // else: use mouse coordinates for context menu
1158 WinQueryPointerPos(HWND_DESKTOP, &ptl);
1159
1160 // give preccSource source emphasis;
1161 // if preccSource == NULL, the whole container will be
1162 // given source emphasis
1163 WinSendMsg(hwndCnr,
1164 CM_SETRECORDEMPHASIS,
1165 (MPARAM)preccSource, // might be NULL for whole container
1166 MPFROM2SHORT(TRUE, // set emphasis
1167 CRA_SOURCE));
1168
1169 // finally, show context menu
1170 brc = WinPopupMenu(HWND_DESKTOP, // menu parent
1171 hwndMenuOwner, // menu owner
1172 hMenu,
1173 (SHORT)ptl.x,
1174 (SHORT)ptl.y,
1175 0, // ID
1176 PU_NONE
1177 | PU_MOUSEBUTTON1
1178 | PU_KEYBOARD
1179 | PU_HCONSTRAIN
1180 | PU_VCONSTRAIN);
1181 }
1182
1183 return (brc);
1184}
1185
1186/*
1187 *@@ cnrhQuerySourceRecord:
1188 * this helper function evaluates a given container
1189 * to find out which records have been selected while
1190 * a context menu is open.
1191 *
1192 * This is for implementing a WPS-like (probably CUA) behavior
1193 * when invoking actions on container records. That is:
1194 *
1195 * 1) If the user opens a context menu on a selected object,
1196 * the selected action should be invoked on _all_ selected
1197 * objects.
1198 *
1199 * 2) If the user opens a context menu on an object which is
1200 * _not_ selected, the action should be invoked on that
1201 * object only (which should be given source emphasis),
1202 * no matter what other objects are selected.
1203 *
1204 * This function expects in preccSource the record core which
1205 * currently has (or just had) source emphasis.
1206 *
1207 * 1) In your own programs, you should have used cnrhShowContextMenu
1208 * above, which sets record source emphasis correctly. Unfortunately,
1209 * PM posts WM_MENUEND _before_ WM_COMMAND, so if you remove source
1210 * emphasis in WM_MENUEND, it is unknown which record was selected at
1211 * the time WM_COMMAND comes in... so you need to store that record
1212 * and pass it to this function later. Sorry.
1213 *
1214 * 2) With the WPS, this function works within the wpMenuItemSelected
1215 * method, because that one is invoked during the processing of
1216 * WM_COMMAND and the WPS automatically does the source emphasis
1217 * stuff right.
1218 *
1219 * The result of this evaluation is stored in *pulSelection,
1220 * which can be:
1221 *
1222 * -- SEL_WHITESPACE (1): the context menu was opened on the
1223 * whitespace of the container (preccSource
1224 * is NULL);
1225 * this func then returns NULL also.
1226 * -- SEL_SINGLESEL (2): the context menu was opened for a
1227 * single selected object:
1228 * this func then returns that record core
1229 * (which is preccSource).
1230 * -- SEL_MULTISEL (3): the context menu was opened on one
1231 * of a multitude of selected record;
1232 * this func then returns the first of the
1233 * selected records. Use
1234 * cnrhQueryNextSelectedRecord to get the others.
1235 * -- SEL_SINGLEOTHER (4): the context menu was opened for a
1236 * single record _other_ than the selected
1237 * records:
1238 * this func then returns that record
1239 * (which is preccSource).
1240 *
1241 *@@added V0.9.0 [umoeller]
1242 */
1243
1244PRECORDCORE cnrhQuerySourceRecord(HWND hwndCnr, // in: cnr
1245 PRECORDCORE preccSource, // in: record which had source emphasis
1246 PULONG pulSelection) // out: selection flags
1247{
1248 PRECORDCORE preccReturn = NULL;
1249
1250 if (preccSource == NULL)
1251 {
1252 // this probably means that the whole container has
1253 // source emphasis --> context menu on folder whitespace
1254 *pulSelection = SEL_WHITESPACE;
1255 // and return NULL
1256 }
1257 else if (((LONG)preccSource) != -1) // no error?
1258 {
1259 // check whether the source record is also selected
1260 if ((preccSource->flRecordAttr & CRA_SELECTED) == 0)
1261 {
1262 // no:
1263 // only one object, but not one of the selected ones
1264 // (if any at all)
1265 preccReturn = preccSource;
1266 *pulSelection = SEL_SINGLEOTHER;
1267 }
1268 else
1269 {
1270 // yes, source record _is_ selected:
1271 // check whether we have more than one selected record?
1272
1273 // get first selected record
1274 PRECORDCORE preccSelected = (PRECORDCORE)WinSendMsg(hwndCnr,
1275 CM_QUERYRECORDEMPHASIS,
1276 (MPARAM)CMA_FIRST,
1277 (MPARAM)CRA_SELECTED);
1278 // return that one
1279 preccReturn = preccSelected;
1280
1281 // are several objects selected?
1282 preccSelected = (PRECORDCORE)WinSendMsg(hwndCnr,
1283 CM_QUERYRECORDEMPHASIS,
1284 (MPARAM)preccSelected,
1285 // get next selected
1286 (MPARAM)CRA_SELECTED);
1287 if (preccSelected)
1288 // several objects
1289 *pulSelection = SEL_MULTISEL;
1290 else
1291 // only one object
1292 *pulSelection = SEL_SINGLESEL;
1293 }
1294 }
1295
1296 return (preccReturn);
1297}
1298
1299/*
1300 *@@ cnrhQueryNextSelectedRecord:
1301 * if cnrhQuerySourceRecord above returns SEL_MULTISEL
1302 * you can use this helper func to loop thru all the
1303 * selected records. This will return the next record
1304 * after preccCurrent which is selected or NULL if it's the last.
1305 *
1306 * If you're not using cnrhQuerySourceRecord (because your
1307 * records do not have source emphasis), you can also call
1308 * this function with (preccCurrent == CMA_FIRST) to get the
1309 * first selected record core.
1310 */
1311
1312PRECORDCORE cnrhQueryNextSelectedRecord(HWND hwndCnr,
1313 PRECORDCORE preccCurrent)
1314{
1315 PRECORDCORE preccReturn = 0;
1316 if (preccCurrent)
1317 {
1318 PRECORDCORE preccNext = (PRECORDCORE)WinSendMsg(hwndCnr,
1319 CM_QUERYRECORDEMPHASIS,
1320 (MPARAM)preccCurrent,
1321 (MPARAM)CRA_SELECTED);
1322 if ((preccNext) && ((LONG)preccNext != -1) )
1323 preccReturn = preccNext;
1324 }
1325 return (preccReturn);
1326}
1327
1328/*
1329 *@@category: Helpers\PM helpers\Container helpers\Record relations/iteration
1330 * functions for querying the relation of records and
1331 * iterating through records.
1332 */
1333
1334/* ******************************************************************
1335 *
1336 * Record relations/iteration
1337 *
1338 ********************************************************************/
1339
1340/*
1341 *@@ cnrhQueryRecordIndex:
1342 * returns the "index" of the specified record
1343 * in the specified container. That is, if the
1344 * specified record is the first record in the
1345 * container, 0 is returned. If it's the second,
1346 * 1 is returned, and so on.
1347 *
1348 * Returns -1 if precc could not be found.
1349 *
1350 * Doesn't work in Tree view.
1351 *
1352 *@@added V0.9.3 (2000-04-19) [umoeller]
1353 */
1354
1355LONG cnrhQueryRecordIndex(HWND hwndCnr,
1356 PRECORDCORE precc)
1357{
1358 PRECORDCORE precc2 = (PRECORDCORE)CMA_FIRST;
1359 BOOL fFirstCall = TRUE;
1360 LONG lrc = -1,
1361 lCount = 0;
1362
1363 while (TRUE)
1364 {
1365 precc2 =
1366 (PRECORDCORE)WinSendMsg(hwndCnr,
1367 CM_QUERYRECORD,
1368 (MPARAM)precc2, // ignored on first call
1369 MPFROM2SHORT(
1370 (fFirstCall)
1371 ? CMA_FIRST
1372 : CMA_NEXT,
1373 CMA_ITEMORDER)
1374 );
1375 if ( (precc2 == NULL)
1376 || (precc2 == (PRECORDCORE)-1)
1377 )
1378 // error:
1379 // return -1
1380 break;
1381 else
1382 if (precc2 == precc)
1383 {
1384 // same as search record:
1385 lrc = lCount;
1386 break;
1387 }
1388
1389 // else search on
1390 fFirstCall = FALSE;
1391 lCount++;
1392 }
1393
1394 return (lrc);
1395}
1396
1397/*
1398 *@@ cnrhIsChildOf:
1399 * returns TRUE only if precTest is a child record
1400 * of precParent in a tree view.
1401 *
1402 *@@added V0.9.7 (2000-12-13) [umoeller]
1403 */
1404
1405BOOL cnrhIsChildOf(HWND hwndCnr,
1406 PRECORDCORE precTest, // in: recc to test
1407 PRECORDCORE precParent) // in: parent to test
1408{
1409 BOOL brc = FALSE;
1410 if ((precTest) && (precParent))
1411 {
1412 PRECORDCORE precParentThis = precTest;
1413
1414 while (precParentThis)
1415 {
1416 // first call: get parent of precTest;
1417 // subsequent calls: climb up
1418 precParentThis = (PRECORDCORE)WinSendMsg(hwndCnr,
1419 CM_QUERYRECORD,
1420 precParentThis,
1421 MPFROM2SHORT(CMA_PARENT,
1422 CMA_ITEMORDER));
1423 if (precParentThis == (PRECORDCORE)-1)
1424 break;
1425 else
1426 if (precParentThis == precParent)
1427 {
1428 brc = TRUE;
1429 break;
1430 }
1431 }
1432 }
1433
1434 return (brc);
1435}
1436
1437/*
1438 *@@ cnrhForAllRecords:
1439 * this monster function calls pfnwpCallback
1440 * for really all the records in the container,
1441 * including child records in tree view.
1442 *
1443 * This is extremely useful for cleaning up
1444 * all record cores before a container window
1445 * gets destroyed.
1446 *
1447 * This function recurses for child records.
1448 * On the first call, preccParent should be
1449 * NULL; you may however specify a certain
1450 * record, and this function will call the
1451 * callback only for that record and children.
1452 *
1453 * pfnwpCallback gets called with the following
1454 * parameters:
1455 *
1456 * -- HWND hwnd: hwndCnr, as passed to this func
1457 * -- PRECORDCORE precc: current record core, as
1458 * determined by this func.
1459 * -- ULONG ulUser1/2: what you have specified here.
1460 *
1461 * It must be declared as follows:
1462 *
1463 + ULONG EXPENTRY fncb(HWND hwndCnr,
1464 + PRECORDCORE precc,
1465 + ULONG ulUser1,
1466 + ULONG ulUser2)
1467 *
1468 * If the callback returns anything != 0, this
1469 * function stops even before all records have
1470 * been processed. You can use ulUser for a
1471 * pointer to a return value.
1472 *
1473 * This always returns the no. of records which
1474 * were processed.
1475 *
1476 * If you use this function for deleting record
1477 * cores, you can be sure that you can delete
1478 * every record, because your callback gets called
1479 * for the child records before the parent record.
1480 *
1481 *@@added V0.9.0 [umoeller]
1482 */
1483
1484ULONG cnrhForAllRecords(HWND hwndCnr,
1485 PRECORDCORE preccParent, // in: NULL for root
1486 PFNCBRECC pfncbRecc, // in: callback
1487 ULONG ulUser1,
1488 ULONG ulUser2)
1489{
1490 PRECORDCORE precc2 = preccParent;
1491 ULONG ulrc = 0;
1492 USHORT usQuery;
1493 BOOL fFirstCall = TRUE;
1494
1495 while (TRUE)
1496 {
1497 if (fFirstCall)
1498 {
1499 // first call:
1500 if (preccParent)
1501 // non-root:
1502 usQuery = CMA_FIRSTCHILD;
1503 else
1504 // NULL == root:
1505 usQuery = CMA_FIRST;
1506 }
1507 else
1508 // subsequent calls:
1509 usQuery = CMA_NEXT; // works as CMA_NEXTCHILD also
1510
1511 precc2 =
1512 (PRECORDCORE)WinSendMsg(hwndCnr,
1513 CM_QUERYRECORD,
1514 (MPARAM)((fFirstCall)
1515 // first call (CMA_FIRSTCHILD or CMA_FIRST):
1516 ? preccParent // ignored for CMA_FIRST
1517 // subsequent calls (CMA_NEXTCHILD or CMA_NEXT):
1518 : precc2), // what we queried last
1519 MPFROM2SHORT(
1520 usQuery, // set above
1521 CMA_ITEMORDER)
1522 );
1523
1524 if ((precc2) && ((ULONG)precc2 != -1))
1525 {
1526 // record found:
1527 // recurse for that record
1528 ulrc += cnrhForAllRecords(hwndCnr,
1529 precc2, // new parent to search
1530 pfncbRecc,
1531 ulUser1,
1532 ulUser2);
1533
1534 // _Pmpf(("Calling callback for %s", precc2->pszIcon));
1535
1536 // call callback
1537 if (pfncbRecc)
1538 if ((*pfncbRecc)(hwndCnr, precc2, ulUser1, ulUser2))
1539 // returns something != NULL:
1540 // stop
1541 break;
1542 ulrc++;
1543 }
1544 else
1545 // no more records or error: get outta here
1546 break;
1547
1548 fFirstCall = FALSE;
1549 }
1550
1551 return (ulrc);
1552}
1553
1554/*
1555 * cnrhForAllChildRecords:
1556 * calls the specified fncbRecc callback for
1557 * the specified recc and all its child records.
1558 *
1559 *@@added V0.9.0 [umoeller]
1560 */
1561
1562/* VOID cnrhForAllChildRecords(HWND hwndCnr,
1563 PRECORDCORE precc,
1564 PFNCBRECC pfncbRecc,
1565 ULONG ulp1,
1566 ULONG ulp2)
1567{
1568 PRECORDCORE precc2 = precc;
1569 (*pfncbRecc)(precc, ulp1, ulp2);
1570 do {
1571 precc2 =
1572 (PRECORDCORE)WinSendMsg(hwndCnr,
1573 CM_QUERYRECORD,
1574 (MPARAM)precc2,
1575 MPFROM2SHORT(
1576 (precc2 == precc)
1577 ? CMA_FIRSTCHILD : CMA_NEXT,
1578 CMA_ITEMORDER)
1579 );
1580 if ((LONG)precc2 == -1)
1581 precc2 = NULL;
1582 if (precc2)
1583 // recurse again
1584 cnrhForAllChildRecords(hwndCnr, precc2, pfncbRecc, ulp1, ulp2);
1585 } while (precc2);
1586} */
1587
1588/*
1589 * cnrhForAllRecords2:
1590 * this is a useful function which calls
1591 * the specified callback function for
1592 * really all records in the container of
1593 * the main window, including child records.
1594 *
1595 * xxx
1596 *
1597 *@@added V0.9.0 [umoeller]
1598 */
1599
1600/* VOID cnrhForAllRecords2(HWND hwndCnr,
1601 PFNCBRECC pfncbRecc,
1602 ULONG ulp1,
1603 ULONG ulp2)
1604{
1605 PRECORDCORE precc2 = NULL;
1606 do {
1607 precc2 =
1608 (PRECORDCORE)WinSendMsg(hwndCnr,
1609 CM_QUERYRECORD,
1610 (MPARAM)precc2,
1611 MPFROM2SHORT(
1612 ((precc2 == NULL) ? CMA_FIRST : CMA_NEXT),
1613 CMA_ITEMORDER)
1614 );
1615 if ((LONG)precc2 == -1)
1616 precc2 = NULL;
1617 if (precc2)
1618 // recurse again
1619 cnrhForAllChildRecords(hwndCnr, precc2, pfncbRecc, ulp1, ulp2);
1620 } while (precc2);
1621} */
1622
1623/*
1624 * cnrhForAllParentRecords:
1625 * just as above, but climbs up instead.
1626 * The first call of the callback will be
1627 * for the parent record of precc.
1628 *
1629 *@@added V0.9.0 [umoeller]
1630 */
1631
1632/* VOID cnrhForAllParentRecords(HWND hwndCnr,
1633 PRECORDCORE precc,
1634 PFNCBRECC pfncbRecc,
1635 ULONG ulp1,
1636 ULONG ulp2)
1637{
1638 PRECORDCORE precc2 = precc;
1639 do {
1640 precc2 =
1641 (PRECORDCORE)WinSendMsg(hwndCnr,
1642 CM_QUERYRECORD,
1643 (MPARAM)precc2,
1644 MPFROM2SHORT(CMA_PARENT,
1645 CMA_ITEMORDER)
1646 );
1647 if ((LONG)precc2 == -1)
1648 precc2 = NULL;
1649 if (precc2)
1650 (*pfncbRecc)(precc2, ulp1, ulp2);
1651 } while (precc2);
1652} */
1653
1654/*
1655 *@@category: Helpers\PM helpers\Container helpers\Miscellaneous
1656 */
1657
1658/* ******************************************************************
1659 *
1660 * Miscellaneous
1661 *
1662 ********************************************************************/
1663
1664/*
1665 *@@ cnrhQueryCnrFromFrame:
1666 * find the handle of a frame window's container; we do this
1667 * by enumerating all the frame's child windows and comparing
1668 * their window classes to the WC_CONTAINER code.
1669 * This is not terribly fast, so use this func economically.
1670 * Returns NULLHANDLE if not found.
1671 */
1672
1673HWND cnrhQueryCnrFromFrame(HWND hwndFrame)
1674{
1675 HENUM henum;
1676 CHAR szClassName[256];
1677 HWND hwndCnr = NULLHANDLE,
1678 hwndTemp = NULLHANDLE;
1679
1680 if (hwndFrame)
1681 {
1682 henum = WinBeginEnumWindows(hwndFrame);
1683 if (henum)
1684 {
1685 do
1686 {
1687 hwndTemp = WinGetNextWindow(henum);
1688 if (hwndTemp)
1689 {
1690 if (WinQueryClassName(hwndTemp, 250, szClassName))
1691 if (strcmp(szClassName, "#37") == 0)
1692 // unbelievable, this is PM's code for WC_CONTAINER...
1693 hwndCnr = hwndTemp;
1694 }
1695 } while (hwndTemp);
1696 }
1697 WinEndEnumWindows(henum);
1698 }
1699
1700 return hwndCnr;
1701}
1702
1703/*
1704 *@@ cnrhInitDrag:
1705 * this sets up the necessary structures to begin dragging
1706 * a record core from a container. This helper func should be
1707 * called if your container should support being the source
1708 * window of a direct manipulation.
1709 *
1710 * This should get called in three situations:
1711 *
1712 * -- the container sends CN_INITDRAG ("real" d'n'd desired by user);
1713 *
1714 * -- the container sends us CN_PICKUP (Alt+MB2 pressed);
1715 *
1716 * -- the user has selected "Pickup" from a record core's
1717 * context menu (ID_XSMI_FILETYPES_PICKUP command).
1718 * In that case, you can also call this function with
1719 * usNotifyCode == CN_PICKUP.
1720 *
1721 * In all three cases, preccDrag must be the record core
1722 * which is to be dragged.
1723 *
1724 * Depending on usNotifyCode, this function, after having allocated
1725 * the necessary data, will do the following:
1726 *
1727 * 1) If (usNotifyCode == CN_PICKUP), we will initiate a non-modal
1728 * (lazy) drag (DrgLazyDrag). This function will then return
1729 * after the records have been given "picked" emphasis.
1730 *
1731 * Note: You must intercept CN_DROPNOTIFY in your window proc
1732 * to clean up resources later. For this, call:
1733 *
1734 + DrgDeleteDraginfoStrHandles(pdrgInfo);
1735 + DrgFreeDraginfo(pdrgInfo);
1736 *
1737 * 2) However, if (usNotifyCode == CN_INITDRAG), we will start
1738 * a regular modal drag here by calling DrgDrag. This function
1739 * will _not_ return until the object has been dropped or d'n'd
1740 * has been cancelled. PM establishes another message loop
1741 * internally for this. In this case, this function managed
1742 * cleanup automatically.
1743 *
1744 * This function supports one single record core only. The following
1745 * information will be set in the DRAGITEM structure:
1746 *
1747 * -- ulItemID will be set to the preccDrag so that the target
1748 * window can access the dragged record.
1749 *
1750 * -- hstrSourceName == hstrTargetName gets the RECORDCORE.pszIcon.
1751 *
1752 * The drag icon will be a default system file icon.
1753 *
1754 * Preconditions:
1755 *
1756 * -- pszIcon must be set in the RECORDCORE. This is used for
1757 * the item source name. This must not be NULL.
1758 */
1759
1760PDRAGINFO cnrhInitDrag(HWND hwndCnr,
1761 // in: source container window
1762 PRECORDCORE preccDrag,
1763 // in: record to be dragged (only one supported)
1764 USHORT usNotifyCode,
1765 // in: CN_INITDRAG or CN_PICKUP
1766 PSZ pszRMF,
1767 // in: rendering mechanism and format,
1768 // e.g. "(DRM_MYFILETYPE)x(DRF_UNKNOWN)"
1769 USHORT usSupportedOps)
1770 // stored in DRAGITEM.fsSupportedOps,
1771 // one or several of DO_COPYABLE, DO_MOVEABLE, DO_LINKABLE
1772{
1773 DRAGIMAGE drgImage;
1774 PDRAGINFO pdrgInfo = NULL;
1775
1776 memset(&drgImage, 0, sizeof(drgImage));
1777 pdrgInfo = DrgAllocDraginfo(1); // one item only
1778 if (pdrgInfo)
1779 {
1780 DRAGITEM drgItem;
1781 memset(&drgItem, 0, sizeof(drgItem));
1782
1783 drgItem.hwndItem = hwndCnr;
1784 drgItem.ulItemID = (ULONG)preccDrag;
1785 // we use this to store the container rec
1786 drgItem.hstrType = DrgAddStrHandle(DRT_UNKNOWN);
1787 // application defined
1788 drgItem.hstrRMF = DrgAddStrHandle(pszRMF);
1789 drgItem.hstrContainerName = 0;
1790 drgItem.hstrSourceName = DrgAddStrHandle(preccDrag->pszIcon);
1791 drgItem.hstrTargetName = drgItem.hstrSourceName;
1792 drgItem.fsSupportedOps = usSupportedOps;
1793
1794 // set the DRAGITEM struct into the memory
1795 // allocated by DrgAllocDraginfo()
1796 DrgSetDragitem(pdrgInfo,
1797 &drgItem,
1798 sizeof(DRAGITEM),
1799 0); // item index
1800
1801 // fill in the DRAGIMAGE structure
1802 drgImage.cb = sizeof(DRAGIMAGE);
1803 drgImage.hImage = WinQuerySysPointer(HWND_DESKTOP,
1804 SPTR_FILE,
1805 FALSE);
1806 // pointer used for dragging; we
1807 // use a dull default file icon
1808 drgImage.fl = DRG_ICON; // hImage is an HPOINTER
1809 drgImage.cxOffset = 0; // 5 * iOffset; // Image offset from mouse pointer
1810 drgImage.cyOffset = 0; // 5 * iOffset; // Image offset from mouse pointer
1811
1812 // set source emphasis for the container record
1813 WinSendMsg(hwndCnr,
1814 CM_SETRECORDEMPHASIS,
1815 (MPARAM)preccDrag,
1816 MPFROM2SHORT(TRUE,
1817 (usNotifyCode == CN_INITDRAG)
1818 // for dragging: source emphasis
1819 ? CRA_SOURCE
1820 // for lazy drag: picked emphasis
1821 : CRA_PICKED));
1822
1823 if (usNotifyCode == CN_INITDRAG)
1824 {
1825 // "real" dragging:
1826 // call modal function for drag'n'drop.
1827 // This does not return until either
1828 // d'n'd has been cancelled or the
1829 // record core has been dropped.
1830 /* HWND hwndTarget = */ DrgDrag(hwndCnr,
1831 pdrgInfo,
1832 &drgImage,
1833 1, // drag image count
1834 VK_ENDDRAG, // system drag button
1835 NULL); // reserved
1836
1837 // since it's the source which is responsible
1838 // for cleaning up the resources, this is
1839 // what we do now (we had a modal d'n'd)
1840 DrgDeleteDraginfoStrHandles(pdrgInfo);
1841 DrgFreeDraginfo(pdrgInfo);
1842
1843 // remove source emphasis for the container record
1844 WinSendMsg(hwndCnr,
1845 CM_SETRECORDEMPHASIS,
1846 (MPARAM)preccDrag,
1847 MPFROM2SHORT(FALSE,
1848 CRA_SOURCE));
1849 } // end if (usNotifyCode == CN_INITDRAG)
1850 else
1851 {
1852 // "lazy drag" (CN_PICKUP):
1853 // initiate lazy drag. This function returns
1854 // immediately, since lazy drag is non-modal.
1855 // As a result, we cannot clean up the resources
1856 // here, but need to do this later (CN_DROPNOTIFY).
1857 DrgLazyDrag(hwndCnr,
1858 pdrgInfo,
1859 &drgImage,
1860 1, // drag image count
1861 0); // reserved
1862 }
1863 } // end if (pdrgInfo)
1864
1865 return (pdrgInfo);
1866}
1867
1868/*
1869 *@@ cnrhOwnerDrawRecord:
1870 * this helper func can be called upon receiving
1871 * WM_DRAWITEM for owner-drawing container record
1872 * cores.
1873 *
1874 * Presently, this function supports drawing record
1875 * cores in gray color if the record has the CRA_DISABLED
1876 * style (which, AFAIK, PM ignores per default).
1877 *
1878 * This returns either TRUE or FALSE as an MPARAM, depending
1879 * on whether we have drawn the item. This return value should
1880 * also be the return value of your window procedure.
1881 */
1882
1883MRESULT cnrhOwnerDrawRecord(MPARAM mp2) // in: mp2 of WM_DRAWITEM (POWNERITEM)
1884{
1885 MRESULT mrc = 0;
1886
1887 // get generic DRAWITEM structure
1888 POWNERITEM poi = (POWNERITEM)mp2;
1889
1890 // check if we're to draw the text
1891 // (and not the icon)
1892 if (poi->idItem == CMA_TEXT)
1893 {
1894 // get container-specific draw-item struct
1895 PCNRDRAWITEMINFO pcdii = (PCNRDRAWITEMINFO)poi->hItem;
1896
1897 if (((pcdii->pRecord->flRecordAttr) & CRA_DISABLED) == 0)
1898 {
1899 /*
1900 // not disabled == valid WPS class
1901 if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
1902 {
1903 // not disabled, but selected:
1904 lBackground = winhQueryPresColor(hwndDlg, PP_HILITEBACKGROUNDCOLOR, SYSCLR_HILITEBACKGROUND);
1905 lForeground = winhQueryPresColor(hwndDlg, PP_HILITEFOREGROUNDCOLOR, SYSCLR_HILITEFOREGROUND);
1906 }
1907 else
1908 {
1909 // not disabled, not selected:
1910 lBackground = winhQueryPresColor(hwndDlg, PP_BACKGROUNDCOLOR, SYSCLR_BACKGROUND);
1911 lForeground = winhQueryPresColor(hwndDlg, PP_FOREGROUNDCOLOR, SYSCLR_WINDOWTEXT);
1912 } */
1913 mrc = FALSE;
1914 // let cnr draw the thing
1915 }
1916 else
1917 {
1918 // CRA_DISABLED:
1919
1920 ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT;
1921 RECTL rcl2;
1922
1923 // set draw colors
1924 LONG lBackground,
1925 lForeground;
1926
1927 // switch to RGB
1928 GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL);
1929
1930 if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
1931 {
1932 // disabled and selected:
1933 lBackground = WinQuerySysColor(HWND_DESKTOP,
1934 SYSCLR_SHADOWTEXT, 0);
1935 lForeground = winhQueryPresColor(poi->hwnd,
1936 PP_BACKGROUNDCOLOR,
1937 FALSE, // no inherit
1938 SYSCLR_WINDOW);
1939 }
1940 else
1941 {
1942 // disabled and not selected:
1943 lBackground = winhQueryPresColor(poi->hwnd,
1944 PP_BACKGROUNDCOLOR,
1945 FALSE,
1946 SYSCLR_WINDOW);
1947 lForeground = WinQuerySysColor(HWND_DESKTOP,
1948 SYSCLR_SHADOWTEXT, 0);
1949 }
1950
1951 memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2));
1952 /* WinDrawText(poi->hps,
1953 strlen(pcdii->pRecord->pszText),
1954 pcdii->pRecord->pszText,
1955 &rcl2,
1956 lForeground, // foreground
1957 lBackground,
1958 flCmd); */
1959
1960 GpiSetBackColor(poi->hps, lBackground);
1961 GpiSetColor(poi->hps, lForeground);
1962
1963 winhDrawFormattedText(poi->hps,
1964 &rcl2,
1965 pcdii->pRecord->pszText,
1966 flCmd);
1967
1968 mrc = (MPARAM)TRUE; // tell cnr that we've drawn the item
1969 }
1970 } else
1971 mrc = (MPARAM)FALSE; // tell cnr to draw the item
1972
1973 return (mrc);
1974}
1975
1976/*
1977 *@@ cnrhDateTimeDos2Win:
1978 * this converts the information in a Control Program
1979 * DATETIME structure (as returned by DosGetDateTime)
1980 * to the CDATE and CTIME structures used by containers.
1981 *
1982 * If any of the target pointers is NULL, that data is
1983 * not converted.
1984 */
1985
1986BOOL cnrhDateTimeDos2Win(DATETIME* pdt, // in: Dos format date and time
1987 CDATE* pcdate, // out: container format date
1988 CTIME* pctime) // out: container format time
1989{
1990 if (pdt)
1991 {
1992 if (pcdate)
1993 {
1994 pcdate->day = pdt->day;
1995 pcdate->month = pdt->month;
1996 pcdate->year = pdt->year;
1997 }
1998 if (pctime)
1999 {
2000 pctime->seconds = pdt->seconds;
2001 pctime->minutes = pdt->minutes;
2002 pctime->hours = pdt->hours;
2003 }
2004 return (TRUE);
2005 }
2006 else
2007 return (FALSE);
2008}
2009
2010/*
2011 *@@ cnrhDateDos2Win:
2012 * converts an FDATE structure (Control program)
2013 * to a container CDATE structure.
2014 */
2015
2016BOOL cnrhDateDos2Win(FDATE* pfd, // in: DOS date
2017 CDATE* pcd) // out: container date
2018{
2019 if ((pfd) && (pcd))
2020 {
2021 pcd->day = pfd->day;
2022 pcd->month = pfd->month;
2023 pcd->year = pfd->year + 1980;
2024 return (TRUE);
2025 }
2026 else
2027 return (FALSE);
2028}
2029
2030/*
2031 *@@ cnrhTimeDos2Win:
2032 * converts an FTIME structure (Control program)
2033 * to a container CTIME structure.
2034 */
2035
2036BOOL cnrhTimeDos2Win(FTIME* pft, // in: DOS time
2037 CTIME* pct) // out: container time
2038{
2039 if ((pft) && (pct))
2040 {
2041 pct->seconds = pft->twosecs * 2;
2042 pct->minutes = pft->minutes;
2043 pct->hours = pft->hours;
2044 pct->ucReserved = 0;
2045 return (TRUE);
2046 }
2047 else
2048 return (FALSE);
2049}
Note: See TracBrowser for help on using the repository browser.