source: trunk/src/helpers/cctl_splitwin.c@ 15

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

Major updates; timers, LVM, miscellaneous.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1
2/*
3 *@@sourcefile cctl.splitwin.c:
4 * implementation for split windows.
5 * See comctl.c for an overview.
6 *
7 * This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller].
8 *
9 * Note: Version numbering in this file relates to XWorkplace version
10 * numbering.
11 *
12 *@@header "helpers\comctl.h"
13 *@@added V0.9.3 (2000-05-21) [umoeller].
14 */
15
16/*
17 * Copyright (C) 1997-2000 Ulrich M”ller.
18 * This file is part of the "XWorkplace helpers" source package.
19 * This is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published
21 * by the Free Software Foundation, in version 2 as it comes in the
22 * "COPYING" file of the XWorkplace main distribution.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 */
28
29#define OS2EMX_PLAIN_CHAR
30 // this is needed for "os2emx.h"; if this is defined,
31 // emx will define PSZ as _signed_ char, otherwise
32 // as unsigned char
33
34#define INCL_DOSEXCEPTIONS
35#define INCL_DOSPROCESS
36#define INCL_DOSSEMAPHORES
37#define INCL_DOSERRORS
38
39#define INCL_WINWINDOWMGR
40#define INCL_WINFRAMEMGR
41#define INCL_WINMESSAGEMGR
42#define INCL_WININPUT
43#define INCL_WINPOINTERS
44#define INCL_WINTRACKRECT
45#define INCL_WINTIMER
46#define INCL_WINSYS
47
48#define INCL_WINRECTANGLES /// xxx temporary
49
50#define INCL_WINMENUS
51#define INCL_WINSTATICS
52#define INCL_WINBUTTONS
53#define INCL_WINSTDCNR
54
55#define INCL_GPIPRIMITIVES
56#define INCL_GPILOGCOLORTABLE
57#define INCL_GPILCIDS
58#define INCL_GPIPATHS
59#define INCL_GPIREGIONS
60#define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers
61#include <os2.h>
62
63#include <stdlib.h>
64#include <stdio.h>
65#include <string.h>
66#include <setjmp.h> // needed for except.h
67#include <assert.h> // needed for except.h
68
69#include "setup.h" // code generation and debugging options
70
71#include "helpers\cnrh.h"
72#include "helpers\except.h" // exception handling
73#include "helpers\gpih.h"
74#include "helpers\linklist.h"
75#include "helpers\winh.h"
76
77#include "helpers\comctl.h"
78
79#pragma hdrstop
80
81/*
82 *@@category: Helpers\PM helpers\Window classes\Split windows
83 */
84
85/* ******************************************************************
86 *
87 * Split windows
88 *
89 ********************************************************************/
90
91/*
92 *@@ PaintSplitWindow:
93 * implementation for WM_PAINT in ctl_fnwpSplitWindow.
94 *
95 *@@added V0.9.1 (2000-02-05) [umoeller]
96 */
97
98VOID PaintSplitWindow(HWND hwndSplit)
99{
100 HPS hps = WinBeginPaint(hwndSplit, (HPS)0, NULL);
101 HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
102 PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar,
103 QWL_USER);
104
105 if ((pData->hwndLinked1) && (pData->hwndLinked2))
106 {
107 // "3D-sunk" style?
108 if (pData->sbcd.ulCreateFlags & SBCF_3DSUNK)
109 {
110 // yes: draw sunk frame around split windows
111 POINTL ptl1;
112 SWP swp;
113
114 // switch to RGB mode
115 GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
116
117 WinQueryWindowPos(pData->hwndLinked1, &swp);
118 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
119 ptl1.x = swp.x - 1;
120 ptl1.y = swp.y - 1;
121 GpiMove(hps, &ptl1);
122 ptl1.y = swp.y + swp.cy;
123 GpiLine(hps, &ptl1);
124 ptl1.x = swp.x + swp.cx;
125 GpiLine(hps, &ptl1);
126 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
127 ptl1.y = swp.y - 1;
128 GpiLine(hps, &ptl1);
129 ptl1.x = swp.x - 1;
130 GpiLine(hps, &ptl1);
131
132 WinQueryWindowPos(pData->hwndLinked2, &swp);
133 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
134 ptl1.x = swp.x - 1;
135 ptl1.y = swp.y - 1;
136 GpiMove(hps, &ptl1);
137 ptl1.y = swp.y + swp.cy;
138 GpiLine(hps, &ptl1);
139 ptl1.x = swp.x + swp.cx;
140 GpiLine(hps, &ptl1);
141 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
142 ptl1.y = swp.y - 1;
143 GpiLine(hps, &ptl1);
144 ptl1.x = swp.x - 1;
145 GpiLine(hps, &ptl1);
146 }
147 }
148
149 WinEndPaint(hps);
150}
151
152/*
153 *@@ ctl_fnwpSplitWindow:
154 * this is the window procedure of the "invisible"
155 * split window. One of these windows is created
156 * for each split view and has exactly three children:
157 *
158 * 1) the split bar (ctl_fnwpSplitBar);
159 *
160 * 2) the left or bottom window linked to the split bar;
161 *
162 * 3) the right or top window linked to the split bar.
163 *
164 * See ctlCreateSplitWindow for more info and a detailed
165 * window hierarchy.
166 *
167 * This stand-alone window procedure must be registered.
168 * ctlCreateSplitWindow does this for you.
169 *
170 *@@added V0.9.0 [umoeller]
171 */
172
173MRESULT EXPENTRY ctl_fnwpSplitWindow(HWND hwndSplit, ULONG msg, MPARAM mp1, MPARAM mp2)
174{
175 MRESULT mrc = (MRESULT)0;
176
177 switch(msg)
178 {
179 /*
180 * WM_WINDOWPOSCHANGED:
181 *
182 */
183
184 case WM_WINDOWPOSCHANGED:
185 {
186 // this msg is passed two SWP structs:
187 // one for the old, one for the new data
188 // (from PM docs)
189 PSWP pswpNew = (PSWP)mp1;
190
191 if (pswpNew->fl & SWP_SIZE)
192 {
193 // _Pmpf(("ctl_fnwpSplitWindow, WM_WINDOWPOSCHANGED"));
194 ctlUpdateSplitWindow(hwndSplit);
195 }
196 mrc = WinDefWindowProc(hwndSplit, msg, mp1, mp2);
197 break; }
198
199 /*
200 * WM_PAINT:
201 *
202 */
203
204 case WM_PAINT:
205 PaintSplitWindow(hwndSplit);
206 break;
207
208 /*
209 *@@ SPLM_SETLINKS:
210 * this specifies the windows which the
211 * split window will link. This updates
212 * the internal SPLITBARDATA and changes
213 * the parents of the two subwindows to
214 * the split window.
215 *
216 * Parameters:
217 * -- HWND mp1: left or bottom subwindow
218 * -- HWND mp2: right or top subwindow
219 */
220
221 case SPLM_SETLINKS:
222 {
223 HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
224 PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar,
225 QWL_USER);
226 if (pData)
227 {
228 pData->hwndLinked1 = (HWND)mp1;
229 pData->hwndLinked2 = (HWND)mp2;
230 // change parents of the windows to link
231 WinSetParent(pData->hwndLinked1, hwndSplit,
232 FALSE); // no redraw
233 WinSetParent(pData->hwndLinked2, hwndSplit,
234 FALSE); // no redraw
235 }
236 break; }
237
238 default:
239 mrc = WinDefWindowProc(hwndSplit, msg, mp1, mp2);
240 }
241
242 return (mrc);
243}
244
245/*
246 *@@ TrackSplitBar:
247 * implementation for WM_BUTTON1DOWN in ctl_fnwpSplitBar.
248 *
249 *@@added V0.9.1 (2000-02-05) [umoeller]
250 */
251
252VOID TrackSplitBar(HWND hwndBar,
253 PSPLITBARDATA pData)
254{
255 TRACKINFO track;
256 RECTL rclBar;
257
258 track.cxBorder = 2;
259 track.cyBorder = 2;
260 track.cxGrid = 1;
261 track.cyGrid = 1;
262 track.cxKeyboard = 8;
263 track.cyKeyboard = 8;
264
265 WinQueryWindowRect(hwndBar, &rclBar);
266 WinMapWindowPoints(hwndBar,
267 HWND_DESKTOP, // map to screen coords.
268 (PPOINTL)&rclBar,
269 2); // 2 points == rectangle
270
271 // limit tracking space to parent window;
272 // this is either the client or another split window
273 WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
274 &track.rclBoundary);
275 WinMapWindowPoints(pData->sbcd.hwndParentAndOwner,
276 HWND_DESKTOP, // map to screen coords.
277 (PPOINTL)&track.rclBoundary,
278 2); // 2 points, since we have a RECTL
279
280 // decrease tracking limits by what was
281 // specified by the caller
282 if (pData->sbcd.ulCreateFlags & SBCF_HORIZONTAL)
283 {
284 // horizontal split bar
285 track.rclBoundary.yBottom += pData->sbcd.ulLeftOrBottomLimit;
286 track.rclBoundary.yTop -= pData->sbcd.ulRightOrTopLimit;
287 track.rclBoundary.xLeft = rclBar.xLeft;
288 track.rclBoundary.xRight = rclBar.xRight;
289 }
290 else
291 {
292 // vertical split bar
293 track.rclBoundary.xLeft += pData->sbcd.ulLeftOrBottomLimit;
294 track.rclBoundary.xRight -= pData->sbcd.ulRightOrTopLimit;
295 track.rclBoundary.yBottom = rclBar.yBottom;
296 track.rclBoundary.yTop = rclBar.yTop;
297 }
298
299 // initial tracking rectangle = split bar
300 memcpy(&track.rclTrack, &rclBar, sizeof(rclBar));
301
302 track.ptlMinTrackSize.x =
303 track.ptlMaxTrackSize.x = track.rclTrack.xRight
304 - track.rclTrack.xLeft; // width of status bar
305 track.ptlMinTrackSize.y =
306 track.ptlMaxTrackSize.y = track.rclTrack.yTop
307 - track.rclTrack.yBottom; // height of status bar
308
309 track.fs = TF_MOVE | TF_ALLINBOUNDARY;
310
311 // now do the tracking: this is a modal
312 // operation and returns only after the
313 // mouse has been released
314 if (WinTrackRect(HWND_DESKTOP, 0, &track))
315 {
316 // OK, successfully moved: reposition the
317 // windows which are linked to the split bar
318
319 if (pData->sbcd.ulCreateFlags & SBCF_HORIZONTAL)
320 {
321 // horizontal split bar
322 ULONG ulNewYPos = track.rclTrack.yBottom
323 - track.rclBoundary.yBottom;
324 // add the limit specified by the caller
325 ulNewYPos += pData->sbcd.ulLeftOrBottomLimit;
326
327 if (pData->sbcd.ulCreateFlags & SBCF_PERCENTAGE)
328 {
329 // status bar pos is determined by
330 // a percentage:
331 // well, we'll need a new percentage then
332 RECTL rclClient;
333 WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
334 &rclClient);
335 pData->sbcd.lPos = ulNewYPos
336 * 100 / (rclClient.yTop - rclClient.yBottom);
337 }
338 else
339 // absolute split bar positioning:
340 if (pData->sbcd.lPos > 0)
341 // from bottom: easy
342 pData->sbcd.lPos = ulNewYPos;
343 else
344 {
345 // negative -> from top:
346 RECTL rclClient;
347 WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
348 &rclClient);
349 // calc new negative
350 pData->sbcd.lPos = ulNewYPos - rclClient.yTop;
351 }
352 }
353 else
354 {
355 // vertical split bar:
356 ULONG ulNewXPos = track.rclTrack.xLeft
357 - track.rclBoundary.xLeft;
358 // add the limit specified by the caller
359 ulNewXPos += pData->sbcd.ulLeftOrBottomLimit;
360
361 if (pData->sbcd.ulCreateFlags & SBCF_PERCENTAGE)
362 {
363 // status bar pos is determined by
364 // a percentage:
365 // well, we'll need a new percentage then
366 RECTL rclClient;
367 WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
368 &rclClient);
369 pData->sbcd.lPos = ulNewXPos
370 * 100 / (rclClient.xRight - rclClient.xLeft);
371 }
372 else
373 // absolute split bar positioning:
374 if (pData->sbcd.lPos > 0)
375 // from left: easy
376 pData->sbcd.lPos = ulNewXPos;
377 else
378 {
379 // negative -> from right:
380 RECTL rclClient;
381 WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
382 &rclClient);
383 // calc new negative
384 pData->sbcd.lPos = ulNewXPos - rclClient.xRight;
385 }
386 }
387
388 // update parent (== "split window")
389 ctlUpdateSplitWindow(WinQueryWindow(hwndBar, QW_PARENT));
390 }
391}
392
393/*
394 *@@ PaintSplitBar:
395 * implementation for WM_PAINT in ctl_fnwpSplitBar.
396 *
397 *@@added V0.9.1 (2000-02-05) [umoeller]
398 *@@changed V0.9.1 (2000-02-05) [umoeller]: fixed paint errors with sunken 3D style
399 */
400
401VOID PaintSplitBar(HWND hwndBar,
402 PSPLITBARDATA pData)
403{
404 HPS hps;
405 RECTL rcl,
406 rclBar;
407 POINTL ptl1;
408 hps = WinBeginPaint(hwndBar, NULLHANDLE, &rcl);
409 WinQueryWindowRect(hwndBar, &rclBar);
410 // switch to RGB mode
411 GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
412
413 // inflate top and right, because WinFillRect
414 // considers this inclusive
415 /* rclBar.xRight++;
416 rclBar.yTop++; */
417
418 WinFillRect(hps,
419 &rclBar,
420 WinQuerySysColor(HWND_DESKTOP,
421 SYSCLR_INACTIVEBORDER,
422 0));
423
424 if ((pData->sbcd.ulCreateFlags & SBCF_3DSUNK) == 0)
425 {
426 GpiSetColor(hps,
427 WinQuerySysColor(HWND_DESKTOP,
428 SYSCLR_BUTTONLIGHT,
429 0));
430 // draw left border (bottom to up)
431 ptl1.x = 0;
432 ptl1.y = 0;
433 GpiMove(hps, &ptl1);
434 ptl1.y = (rclBar.yTop - rclBar.yBottom) - 1;
435 if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
436 // vertical:
437 GpiLine(hps, &ptl1);
438 else
439 GpiMove(hps, &ptl1);
440
441 // draw top border (to right)
442 ptl1.x = (rclBar.xRight - rclBar.xLeft) - 1;
443 if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
444 // vertical:
445 GpiMove(hps, &ptl1);
446 else
447 GpiLine(hps, &ptl1);
448
449 GpiSetColor(hps,
450 WinQuerySysColor(HWND_DESKTOP,
451 SYSCLR_BUTTONDARK,
452 0));
453 // draw right border (to bottom)
454 ptl1.y = 0;
455 if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
456 // vertical:
457 GpiLine(hps, &ptl1);
458 else
459 GpiMove(hps, &ptl1);
460
461 if (!(pData->sbcd.ulCreateFlags & SBCF_VERTICAL))
462 {
463 // horizontal:
464 // draw bottom border
465 ptl1.x = 0;
466 GpiLine(hps, &ptl1);
467 }
468 }
469
470 WinEndPaint(hps);
471}
472
473/*
474 *@@ ctl_fnwpSplitBar:
475 * window procedure for all split bars, horizontal and vertical.
476 * This paints the split bar and handles dragging the split bar
477 * and repositioning the "linked" windows afterwards.
478 *
479 * This is not a stand-alone window procedure, but must only
480 * be used with ctlCreateSplitWindow, which creates and subclasses
481 * a static control as necessary.
482 *
483 * See ctlCreateSplitWindow for more info and a detailed
484 * window hierarchy.
485 *
486 *@@added V0.9.0 [umoeller]
487 *@@changed V0.9.1 (99-12-07): fixed memory leak
488 */
489
490MRESULT EXPENTRY ctl_fnwpSplitBar(HWND hwndBar, ULONG msg, MPARAM mp1, MPARAM mp2)
491{
492 PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndBar, QWL_USER);
493
494 PFNWP OldStaticProc = NULL;
495
496 MRESULT mrc = NULL;
497
498 if (pData)
499 {
500 OldStaticProc = pData->OldStaticProc;
501
502 switch(msg)
503 {
504 /*
505 * WM_MOUSEMOVE:
506 * change mouse pointer when over split bar.
507 */
508
509 case WM_MOUSEMOVE:
510 pData->hptrOld = WinSetPointer(HWND_DESKTOP, pData->hptrMove);
511 break;
512
513 /*
514 * WM_BUTTON1DOWN:
515 * this will start moving the split bar.
516 * We use WinTrackRect for this.
517 */
518
519 case WM_BUTTON1DOWN:
520 TrackSplitBar(hwndBar, pData);
521 break;
522
523 /*
524 * WM_PAINT:
525 * paint the split bar
526 */
527
528 case WM_PAINT:
529 PaintSplitBar(hwndBar, pData);
530 break;
531
532 case WM_DESTROY:
533 free (pData); // added V0.9.1 (99-12-07)
534 mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
535 break;
536
537 default:
538 mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
539 }
540 }
541 return (mrc);
542}
543
544/*
545 *@@ ctlCreateSplitWindow:
546 * this creates a new split window view according to
547 * the given SPLITBARCDATA structure. A split view
548 * links two existing windows together with a split
549 * bar in between, which can be moved with the mouse.
550 *
551 * Split windows are used for example in XWorkplace
552 * for the WPS class list object and in WarpIN for
553 * the database.
554 *
555 * After the split view has been created using this
556 * function, all window resizing/positioning is
557 * automatically performed, that is:
558 *
559 * a) if the parent window of the split view (e.g.
560 * the frame) is resized, the subwindows are
561 * adjusted;
562 *
563 * b) if the split bar is moved, the linked windows
564 * are adjusted also.
565 *
566 * <B>Creating a split view</B>
567 *
568 * To create a split view, you need to perform the
569 * following steps:
570 *
571 * 1) Create two windows that shall be separated by
572 * a split bar. These can be _any_ PM windows:
573 * a simple control window (e.g. a container),
574 * a frame you have created, or even a dialog
575 * which has been loaded using WinLoadDlg.
576 *
577 * Note: With frame windows, make sure they have the
578 * FCF_NOBYTEALIGN flag set, or they'll look funny.
579 *
580 * 2) Fill a SPLITBARCDATA structure with the necessary
581 * data for the split view (see comctl.h for details).
582 *
583 * 3) Call this function with that structure, which creates
584 * and returns the "split window", the invisible parent
585 * of the windows to be split.
586 * See the window hierarchy below.
587 *
588 * 4) Send a SPLM_SETLINKS message to the split window
589 * (returned by this function), with the two windows
590 * to be linked in mp1 and mp2. This has been implemented
591 * using a message so that you can re-link windows later
592 * at any time. (This is how the XWorkplace "WPS Class List"
593 * window does it when the settings notebook is changed.)
594 *
595 * Sending this message will change parentship (not ownership)
596 * of those two windows to the invisible split window.
597 *
598 * 5) Position the split window (which is returned from this
599 * function) within your existing windows using
600 * WinSetWindowPos(..., SWP_SIZE), which will automatically
601 * reposition the two linked subwindows of the split window.
602 * This works because the window procedure of the split
603 * window (ctl_fnwpSplitWindow) handles WM_WINDOWPOSCHANGED to
604 * recalculate the positions of the child windows.
605 *
606 * This function returns the HWND of the "split window".
607 * The handle of the split _bar_, if you absolutely need it,
608 * can be found using
609 + WinWindowFromID(hwndWhatThisReturns, ID_SPLITBAR).
610 *
611 * After SPLM_SETLINKS, the following window hierarchy
612 * is established (parentship):
613 *
614 + SPLITBARCDATA.hwndClient (whatever you have specified;
615 + | e.g. FID_CLIENT of your frame window.
616 + | You must intercept WM_SIZE and
617 + | call WinSetWindowPos on the "split window".)
618 + |
619 + +-- hwndReturn ("split window" created and returned by this
620 + | function; uses ctl_fnwpSplitWindow)
621 + |
622 + +-- hwndLink1 with SPLM_SETLINKS (parent changed)
623 + | |
624 + | +-- ... (your child windows remain untouched)
625 + |
626 + +-- ID_SPLITBAR (uses ctl_fnwpSplitBar)
627 + |
628 + +-- hwndLink2 with SPLM_SETLINKS (parent changed)
629 + |
630 + +-- ... (your child windows remain untouched)
631 *
632 * Note that only parentship of hwndSplit1 and hwndSplit2
633 * is changed. Ownership remains untouched. So you can specify
634 * any window as the owner of hwndLink1/2 so that messages
635 * can be forwarded properly.
636 *
637 * After the above hierarchy has been established, there are
638 * two situations where the "linked" windows will be repositioned
639 * and/or resized:
640 *
641 * 1) ctl_fnwpSplitBar will automatically resize and reposition
642 * the left and right "linked" windows if the user moves the
643 * split bar.
644 *
645 * 2) If the "split window" itself receives WM_WINDOWPOSCHANGED,
646 * e.g. because WinSetWindowPos has been invoked on the
647 * split window (which you should do when WM_SIZE is received
648 * by your parent window), the "linked" windows will
649 * automatically be repositioned and resized. This is done
650 * in ctl_fnwpSplitWindow.
651 *
652 * As a result, you must implement the following in your window
653 * procedures for the windows passed to this function:
654 *
655 * 1) The window procedure of SPLITBARCDATA.hwndClient (the
656 * parent of the split window) must intercept WM_SIZE and
657 * do a WinSetWindowPos on the split window. This will
658 * readjust the split bar and SPLITBARCDATA.hwndLink1/2.
659 *
660 * 2) The two linked windows should in turn handle WM_SIZE
661 * correctly because whenever the split window is resized,
662 * it invokes a WinSetWindowPos on SPLITBARCDATA.hwndLink1/2
663 * in turn.
664 *
665 * If you're using a single standard control as your subwindow
666 * (e.g. a container), this is no problem. However, if you
667 * specify frame windows, you might want to reposition
668 * the controls in those windows in turn.
669 *
670 * Note that dialog windows do not receive WM_SIZE;
671 * you'll need to handle WM_WINDOWPOSCHANGED instead.
672 *
673 * 3) Your window procedure should forward WM_SYSCOMMAND to
674 * the owner (top) window so that Alt-F4 etc. hotkeys
675 * still work.
676 *
677 * If you wish to <B>nest split windows,</B> you can do so by
678 * specifying the "split window" (the HWND which is returned
679 * by this function) as the "hwndLink1/2" to another call
680 * of this function. This way you can create a complex
681 * split window hierarchy (similar to what Netscape does
682 * with the FRAMESET tag). So to create a split view like
683 * this:
684 *
685 + +---------+------------+
686 + | | |
687 + | | 2 |
688 + | | |
689 + | 1 +------------+
690 + | | |
691 + | | 3 |
692 + | | |
693 + +---------+------------+
694 *
695 * First invoke ctlCreateSplitWindow to link "2" and "3"
696 * together (creating a horizontal split bar), which returns
697 * a "split window"; then link "1" and that split window
698 * together again.
699 *
700 *@@added V0.9.0 [umoeller]
701 */
702
703HWND ctlCreateSplitWindow(HAB hab,
704 PSPLITBARCDATA psbcd) // in: split window control data
705{
706 HWND hwndSplit = NULLHANDLE,
707 hwndBar = NULLHANDLE;
708
709 if (psbcd)
710 {
711 // register "split window" class
712 WinRegisterClass(hab,
713 WC_SPLITWINDOW,
714 ctl_fnwpSplitWindow,
715 CS_SIZEREDRAW | CS_SYNCPAINT,
716 0); // additional bytes to reserve
717
718 hwndSplit = WinCreateWindow(psbcd->hwndParentAndOwner, // parent
719 WC_SPLITWINDOW,
720 "",
721 WS_VISIBLE,
722 0, 0, 10, 10,
723 psbcd->hwndParentAndOwner, // owner
724 HWND_TOP,
725 psbcd->ulSplitWindowID,
726 NULL,
727 NULL);
728 if (hwndSplit)
729 {
730 hwndBar = WinCreateWindow(psbcd->hwndParentAndOwner, // parent
731 WC_STATIC,
732 "",
733 WS_VISIBLE // wnd style
734 | SS_TEXT,
735 0, 0, 10, 10,
736 psbcd->hwndParentAndOwner, // owner
737 HWND_TOP,
738 ID_SPLITBAR, // win ID
739 NULL, // cdata
740 NULL // presparams
741 );
742 if (hwndBar)
743 {
744 // create SPLITBARDATA to store in split bar's QWL_USER
745 PSPLITBARDATA pData = (PSPLITBARDATA)malloc(sizeof(SPLITBARDATA));
746 if (pData)
747 {
748 // set parent for split bar
749 WinSetParent(hwndBar, hwndSplit, FALSE);
750
751 memset(pData, 0, sizeof(SPLITBARDATA));
752
753 // copy control data
754 memcpy(&(pData->sbcd), psbcd, sizeof(SPLITBARCDATA));
755 // set other data
756 /* WinQueryWindowRect(hwndBar, &(pData->rclBar));
757 (pData->rclBar.xRight)--;
758 (pData->rclBar.yTop)--; */
759 // subclass static control to make it a split bar
760 pData->OldStaticProc = WinSubclassWindow(hwndBar, ctl_fnwpSplitBar);
761 pData->hptrOld = NULLHANDLE;
762 pData->hptrMove = WinQuerySysPointer(HWND_DESKTOP,
763 (psbcd->ulCreateFlags & SBCF_HORIZONTAL)
764 ? SPTR_SIZENS
765 : SPTR_SIZEWE,
766 FALSE); // don't make copy
767 pData->fCaptured = FALSE;
768 pData->hwndLinked1 =
769 pData->hwndLinked2 = NULLHANDLE;
770
771 WinSetWindowULong(hwndBar, QWL_USER, (ULONG)pData);
772 }
773 }
774 }
775 }
776
777 return (hwndSplit);
778}
779
780/*
781 *@@ ctlUpdateSplitWindow:
782 * this function takes a split window as input and
783 * repositions all its children (the split bars
784 * and the other subwindows which are separated by the
785 * split bars) according to the parent.
786 *
787 * This function gets called from ctl_fnwpSplitWindow
788 * when WM_SIZE is received. Normally, you won't have
789 * to call this function independently; you should do
790 * a WinSetWindowPos on the split window instead.
791 *
792 *@@added V0.9.0 [umoeller]
793 */
794
795BOOL ctlUpdateSplitWindow(HWND hwndSplit)
796{
797 BOOL brc = FALSE;
798 HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
799
800 if (hwndSplitBar)
801 {
802 PSPLITBARDATA psbd = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER);
803
804 if (psbd)
805 {
806 PSPLITBARCDATA psbcd = &(psbd->sbcd);
807 RECTL rclSplit,
808 rclBar;
809 ULONG ul3DOfs = 0;
810
811 // _Pmpf(("Entering ctlUpdateSplitWindow for hwndSplit 0x%lX", hwndSplit));
812
813 // query the rectangle of the split window's parent;
814 // this is either the client or another split window
815 WinQueryWindowRect(hwndSplit, &rclSplit);
816
817 /* _Pmpf((" rect: %d, %d, %d, %d",
818 rclSplit.xLeft,
819 rclSplit.yBottom,
820 rclSplit.xRight - rclSplit.xLeft,
821 rclSplit.yTop - rclSplit.yBottom)); */
822
823 // set anti-recursion flag;
824 // this is neccessary, because ctl_fnwpSplitWindow
825 // calls this func again when
826 // WM_WINDOWPOSCHANGED comes in
827 // psbd->fNoAdjust = TRUE;
828 // set split window to the same
829 /* WinSetWindowPos(hwndSplit, HWND_TOP,
830 rclSplit.xLeft,
831 rclSplit.yBottom,
832 rclSplit.xRight - rclSplit.xLeft,
833 rclSplit.yTop - rclSplit.yBottom,
834 SWP_MOVE | SWP_SIZE); */
835 // psbd->fNoAdjust = FALSE;
836
837 // update split bar
838 if (psbcd->ulCreateFlags & SBCF_HORIZONTAL)
839 {
840 // _Pmpf((" Calc horizontal"));
841 // horizontal split bar:
842 if (psbcd->ulCreateFlags & SBCF_PERCENTAGE)
843 // take height of client and apply percentage
844 rclBar.yBottom = (rclSplit.yTop - rclSplit.yBottom)
845 * psbcd->lPos
846 / 100;
847 else
848 if (psbcd->lPos > 0)
849 // offset from bottom:
850 rclBar.yBottom = psbcd->lPos;
851 else
852 // offset from right:
853 rclBar.yBottom = (rclSplit.yTop - rclSplit.yBottom)
854 + psbcd->lPos; // which is negative
855
856 rclBar.yTop = rclBar.yBottom + WinQuerySysValue(HWND_DESKTOP,
857 SV_CXSIZEBORDER);
858 rclBar.xLeft = 0;
859 // take width of client
860 rclBar.xRight = (rclSplit.xRight - rclSplit.xLeft);
861 }
862 else
863 {
864 // _Pmpf((" Calc vertical"));
865 // vertical split bar:
866 if (psbcd->ulCreateFlags & SBCF_PERCENTAGE)
867 // take width of client and apply percentage
868 rclBar.xLeft = (rclSplit.xRight - rclSplit.xLeft)
869 * psbcd->lPos
870 / 100;
871 else
872 if (psbcd->lPos > 0)
873 // offset from left:
874 rclBar.xLeft = psbcd->lPos;
875 else
876 // offset from right:
877 rclBar.xLeft = (rclSplit.xRight - rclSplit.xLeft)
878 + psbcd->lPos; // which is negative
879
880 rclBar.xRight = rclBar.xLeft + WinQuerySysValue(HWND_DESKTOP,
881 SV_CXSIZEBORDER);
882 rclBar.yBottom = 0;
883 // take height of client
884 rclBar.yTop = (rclSplit.yTop - rclSplit.yBottom);
885 }
886
887 // reposition split bar
888 brc = WinSetWindowPos(hwndSplitBar,
889 HWND_TOP,
890 rclBar.xLeft,
891 rclBar.yBottom,
892 rclBar.xRight - rclBar.xLeft,
893 rclBar.yTop - rclBar.yBottom,
894 SWP_MOVE | SWP_SIZE);
895
896 /* _Pmpf((" Set splitbar hwnd %lX to %d, %d, %d, %d; rc: %d",
897 hwndSplitBar,
898 rclBar.xLeft,
899 rclBar.yBottom,
900 rclBar.xRight - rclBar.xLeft,
901 rclBar.yTop - rclBar.yBottom,
902 brc)); */
903
904 // reposition left/bottom window of split bar
905 if (psbcd->ulCreateFlags & SBCF_3DSUNK)
906 ul3DOfs = 1;
907 // else 0
908
909 // now reposition the linked windows
910 if (psbcd->ulCreateFlags & SBCF_HORIZONTAL)
911 {
912 // horizontal:
913 // reposition bottom window of split bar
914 WinSetWindowPos(psbd->hwndLinked1,
915 HWND_TOP,
916 ul3DOfs,
917 ul3DOfs,
918 rclBar.xRight - rclBar.xLeft - ul3DOfs*2,
919 rclBar.yBottom - ul3DOfs*2, // the window rect is non-inclusive
920 SWP_MOVE | SWP_SIZE);
921
922 // reposition top window of split bar
923 WinSetWindowPos(psbd->hwndLinked2,
924 HWND_TOP,
925 ul3DOfs,
926 rclBar.yTop + ul3DOfs, // the window rect is non-inclusive
927 rclBar.xRight - rclBar.xLeft - ul3DOfs*2,
928 rclSplit.yTop - rclBar.yTop - ul3DOfs*2,
929 SWP_MOVE | SWP_SIZE);
930 }
931 else
932 {
933 // vertical:
934 // reposition left window of split bar
935 WinSetWindowPos(psbd->hwndLinked1,
936 HWND_TOP,
937 ul3DOfs,
938 ul3DOfs,
939 rclBar.xLeft - ul3DOfs*2, // the window rect is non-inclusive
940 rclBar.yTop - rclBar.yBottom - ul3DOfs*2,
941 SWP_MOVE | SWP_SIZE);
942
943 // reposition right window of split bar
944 WinSetWindowPos(psbd->hwndLinked2,
945 HWND_TOP,
946 rclBar.xRight + ul3DOfs, // the window rect is non-inclusive
947 ul3DOfs,
948 rclSplit.xRight - rclBar.xRight - ul3DOfs*2,
949 rclBar.yTop - rclBar.yBottom - ul3DOfs*2,
950 SWP_MOVE | SWP_SIZE);
951 }
952
953 // repaint split window (3D frame)
954 WinInvalidateRect(hwndSplit,
955 NULL, // all
956 FALSE); // don't repaint children
957 }
958 }
959
960 return (brc);
961}
962
963/*
964 *@@ ctlQuerySplitPos:
965 * this returns the position of the split bar
966 * (the child control of hwndSplit; see ctlCreateSplitWindow
967 * for the window hierarchy).
968 *
969 * The meaning of the return value depends on what you
970 * specified with ulCreateFlags in the SPLITBARCDATA
971 * structure passed to ctlCreateSplitWindow, that is,
972 * it can be a percentage or an offset from the left
973 * or from the right of the split window.
974 *
975 * This returns NULL upon errors.
976 *
977 *@@added V0.9.0 [umoeller]
978 */
979
980LONG ctlQuerySplitPos(HWND hwndSplit)
981{
982 ULONG lrc = 0;
983
984 // the split bar data is stored in QWL_USER of the
985 // split bar (not the split window)
986 HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
987 if (hwndSplitBar)
988 {
989 PSPLITBARDATA psbd = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER);
990 if (psbd)
991 lrc = psbd->sbcd.lPos;
992 }
993
994 return (lrc);
995}
996
997
Note: See TracBrowser for help on using the repository browser.