home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
xwphescr.zip
/
XWPH0208.ZIP
/
src
/
helpers
/
cctl_splitwin.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-07-05
|
38KB
|
1,010 lines
/*
*@@sourcefile cctl.splitwin.c:
* implementation for split windows.
* See comctl.c for an overview.
*
* This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller].
*
* Note: Version numbering in this file relates to XWorkplace version
* numbering.
*
*@@header "helpers\comctl.h"
*@@added V0.9.3 (2000-05-21) [umoeller].
*/
/*
* Copyright (C) 1997-2000 Ulrich Möller.
* This file is part of the "XWorkplace helpers" source package.
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, in version 2 as it comes in the
* "COPYING" file of the XWorkplace main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define OS2EMX_PLAIN_CHAR
// this is needed for "os2emx.h"; if this is defined,
// emx will define PSZ as _signed_ char, otherwise
// as unsigned char
#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS
#define INCL_WINWINDOWMGR
#define INCL_WINFRAMEMGR
#define INCL_WINMESSAGEMGR
#define INCL_WININPUT
#define INCL_WINPOINTERS
#define INCL_WINTRACKRECT
#define INCL_WINTIMER
#define INCL_WINSYS
#define INCL_WINRECTANGLES /// xxx temporary
#define INCL_WINMENUS
#define INCL_WINSTATICS
#define INCL_WINBUTTONS
#define INCL_WINSTDCNR
#define INCL_GPIPRIMITIVES
#define INCL_GPILOGCOLORTABLE
#define INCL_GPILCIDS
#define INCL_GPIPATHS
#define INCL_GPIREGIONS
#define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers
#include <os2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h> // needed for except.h
#include <assert.h> // needed for except.h
#include "setup.h" // code generation and debugging options
#include "helpers\cnrh.h"
#include "helpers\except.h" // exception handling
#include "helpers\gpih.h"
#include "helpers\linklist.h"
#include "helpers\winh.h"
#include "helpers\comctl.h"
#pragma hdrstop
/*
*@@category: Helpers\PM helpers\Window classes\Split windows
* See cctl_splitwin.c.
*/
/* ******************************************************************
*
* Split windows
*
********************************************************************/
/*
*@@ PaintSplitWindow:
* implementation for WM_PAINT in ctl_fnwpSplitWindow.
*
*@@added V0.9.1 (2000-02-05) [umoeller]
*/
static VOID PaintSplitWindow(HWND hwndSplit)
{
HPS hps = WinBeginPaint(hwndSplit, (HPS)0, NULL);
HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar,
QWL_USER);
if ((pData->hwndLinked1) && (pData->hwndLinked2))
{
// "3D-sunk" style?
if (pData->sbcd.ulCreateFlags & SBCF_3DSUNK)
{
// yes: draw sunk frame around split windows
POINTL ptl1;
SWP swp;
// switch to RGB mode
GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
WinQueryWindowPos(pData->hwndLinked1, &swp);
GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
ptl1.x = swp.x - 1;
ptl1.y = swp.y - 1;
GpiMove(hps, &ptl1);
ptl1.y = swp.y + swp.cy;
GpiLine(hps, &ptl1);
ptl1.x = swp.x + swp.cx;
GpiLine(hps, &ptl1);
GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
ptl1.y = swp.y - 1;
GpiLine(hps, &ptl1);
ptl1.x = swp.x - 1;
GpiLine(hps, &ptl1);
WinQueryWindowPos(pData->hwndLinked2, &swp);
GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
ptl1.x = swp.x - 1;
ptl1.y = swp.y - 1;
GpiMove(hps, &ptl1);
ptl1.y = swp.y + swp.cy;
GpiLine(hps, &ptl1);
ptl1.x = swp.x + swp.cx;
GpiLine(hps, &ptl1);
GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
ptl1.y = swp.y - 1;
GpiLine(hps, &ptl1);
ptl1.x = swp.x - 1;
GpiLine(hps, &ptl1);
}
}
WinEndPaint(hps);
}
/*
*@@ ctl_fnwpSplitWindow:
* this is the window procedure of the "invisible"
* split window. One of these windows is created
* for each split view and has exactly three children:
*
* 1) the split bar (ctl_fnwpSplitBar);
*
* 2) the left or bottom window linked to the split bar;
*
* 3) the right or top window linked to the split bar.
*
* See ctlCreateSplitWindow for more info and a detailed
* window hierarchy.
*
* This stand-alone window procedure must be registered.
* ctlCreateSplitWindow does this for you.
*
*@@added V0.9.0 [umoeller]
*/
MRESULT EXPENTRY ctl_fnwpSplitWindow(HWND hwndSplit, ULONG msg, MPARAM mp1, MPARAM mp2)
{
MRESULT mrc = (MRESULT)0;
switch(msg)
{
/*
* WM_WINDOWPOSCHANGED:
*
*/
case WM_WINDOWPOSCHANGED:
{
// this msg is passed two SWP structs:
// one for the old, one for the new data
// (from PM docs)
PSWP pswpNew = (PSWP)mp1;
if (pswpNew->fl & SWP_SIZE)
{
// _Pmpf(("ctl_fnwpSplitWindow, WM_WINDOWPOSCHANGED"));
ctlUpdateSplitWindow(hwndSplit);
}
mrc = WinDefWindowProc(hwndSplit, msg, mp1, mp2);
break; }
/*
* WM_PAINT:
*
*/
case WM_PAINT:
PaintSplitWindow(hwndSplit);
break;
/*
*@@ SPLM_SETLINKS:
* this specifies the windows which the
* split window will link. This updates
* the internal SPLITBARDATA and changes
* the parents of the two subwindows to
* the split window.
*
* Parameters:
* -- HWND mp1: left or bottom subwindow
* -- HWND mp2: right or top subwindow
*/
case SPLM_SETLINKS:
{
HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar,
QWL_USER);
if (pData)
{
pData->hwndLinked1 = (HWND)mp1;
pData->hwndLinked2 = (HWND)mp2;
// change parents of the windows to link
WinSetParent(pData->hwndLinked1, hwndSplit,
FALSE); // no redraw
WinSetParent(pData->hwndLinked2, hwndSplit,
FALSE); // no redraw
}
break; }
default:
mrc = WinDefWindowProc(hwndSplit, msg, mp1, mp2);
}
return mrc;
}
/*
*@@ TrackSplitBar:
* implementation for WM_BUTTON1DOWN/WM_BUTTON2DOWN in ctl_fnwpSplitBar.
*
*@@added V0.9.1 (2000-02-05) [umoeller]
*/
static VOID TrackSplitBar(HWND hwndBar,
PSPLITBARDATA pData)
{
TRACKINFO track;
RECTL rclBar;
track.cxBorder = 2;
track.cyBorder = 2;
track.cxGrid = 1;
track.cyGrid = 1;
track.cxKeyboard = 8;
track.cyKeyboard = 8;
WinQueryWindowRect(hwndBar, &rclBar);
WinMapWindowPoints(hwndBar,
HWND_DESKTOP, // map to screen coords.
(PPOINTL)&rclBar,
2); // 2 points == rectangle
// limit tracking space to parent window;
// this is either the client or another split window
WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
&track.rclBoundary);
WinMapWindowPoints(pData->sbcd.hwndParentAndOwner,
HWND_DESKTOP, // map to screen coords.
(PPOINTL)&track.rclBoundary,
2); // 2 points, since we have a RECTL
// decrease tracking limits by what was
// specified by the caller
if (pData->sbcd.ulCreateFlags & SBCF_HORIZONTAL)
{
// horizontal split bar
track.rclBoundary.yBottom += pData->sbcd.ulLeftOrBottomLimit;
track.rclBoundary.yTop -= pData->sbcd.ulRightOrTopLimit;
track.rclBoundary.xLeft = rclBar.xLeft;
track.rclBoundary.xRight = rclBar.xRight;
}
else
{
// vertical split bar
track.rclBoundary.xLeft += pData->sbcd.ulLeftOrBottomLimit;
track.rclBoundary.xRight -= pData->sbcd.ulRightOrTopLimit;
track.rclBoundary.yBottom = rclBar.yBottom;
track.rclBoundary.yTop = rclBar.yTop;
}
// initial tracking rectangle = split bar
memcpy(&track.rclTrack, &rclBar, sizeof(rclBar));
track.ptlMinTrackSize.x =
track.ptlMaxTrackSize.x = track.rclTrack.xRight
- track.rclTrack.xLeft; // width of status bar
track.ptlMinTrackSize.y =
track.ptlMaxTrackSize.y = track.rclTrack.yTop
- track.rclTrack.yBottom; // height of status bar
track.fs = TF_MOVE | TF_ALLINBOUNDARY;
// now do the tracking: this is a modal
// operation and returns only after the
// mouse has been released
if (WinTrackRect(HWND_DESKTOP, 0, &track))
{
// OK, successfully moved: reposition the
// windows which are linked to the split bar
if (pData->sbcd.ulCreateFlags & SBCF_HORIZONTAL)
{
// horizontal split bar
ULONG ulNewYPos = track.rclTrack.yBottom
- track.rclBoundary.yBottom;
// add the limit specified by the caller
ulNewYPos += pData->sbcd.ulLeftOrBottomLimit;
if (pData->sbcd.ulCreateFlags & SBCF_PERCENTAGE)
{
// status bar pos is determined by
// a percentage:
// well, we'll need a new percentage then
RECTL rclClient;
WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
&rclClient);
pData->sbcd.lPos = ulNewYPos
* 100 / (rclClient.yTop - rclClient.yBottom);
}
else
// absolute split bar positioning:
if (pData->sbcd.lPos > 0)
// from bottom: easy
pData->sbcd.lPos = ulNewYPos;
else
{
// negative -> from top:
RECTL rclClient;
WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
&rclClient);
// calc new negative
pData->sbcd.lPos = ulNewYPos - rclClient.yTop;
}
}
else
{
// vertical split bar:
ULONG ulNewXPos = track.rclTrack.xLeft
- track.rclBoundary.xLeft;
// add the limit specified by the caller
ulNewXPos += pData->sbcd.ulLeftOrBottomLimit;
if (pData->sbcd.ulCreateFlags & SBCF_PERCENTAGE)
{
// status bar pos is determined by
// a percentage:
// well, we'll need a new percentage then
RECTL rclClient;
WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
&rclClient);
pData->sbcd.lPos = ulNewXPos
* 100 / (rclClient.xRight - rclClient.xLeft);
}
else
// absolute split bar positioning:
if (pData->sbcd.lPos > 0)
// from left: easy
pData->sbcd.lPos = ulNewXPos;
else
{
// negative -> from right:
RECTL rclClient;
WinQueryWindowRect(pData->sbcd.hwndParentAndOwner,
&rclClient);
// calc new negative
pData->sbcd.lPos = ulNewXPos - rclClient.xRight;
}
}
// update parent (== "split window")
ctlUpdateSplitWindow(WinQueryWindow(hwndBar, QW_PARENT));
}
}
/*
*@@ PaintSplitBar:
* implementation for WM_PAINT in ctl_fnwpSplitBar.
*
*@@added V0.9.1 (2000-02-05) [umoeller]
*@@changed V0.9.1 (2000-02-05) [umoeller]: fixed paint errors with sunken 3D style
*/
static VOID PaintSplitBar(HWND hwndBar,
PSPLITBARDATA pData)
{
HPS hps;
RECTL rcl,
rclBar;
POINTL ptl1;
hps = WinBeginPaint(hwndBar, NULLHANDLE, &rcl);
WinQueryWindowRect(hwndBar, &rclBar);
// switch to RGB mode
GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
// inflate top and right, because WinFillRect
// considers this inclusive
/* rclBar.xRight++;
rclBar.yTop++; */
WinFillRect(hps,
&rclBar,
WinQuerySysColor(HWND_DESKTOP,
SYSCLR_INACTIVEBORDER,
0));
if ((pData->sbcd.ulCreateFlags & SBCF_3DSUNK) == 0)
{
GpiSetColor(hps,
WinQuerySysColor(HWND_DESKTOP,
SYSCLR_BUTTONLIGHT,
0));
// draw left border (bottom to up)
ptl1.x = 0;
ptl1.y = 0;
GpiMove(hps, &ptl1);
ptl1.y = (rclBar.yTop - rclBar.yBottom) - 1;
if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
// vertical:
GpiLine(hps, &ptl1);
else
GpiMove(hps, &ptl1);
// draw top border (to right)
ptl1.x = (rclBar.xRight - rclBar.xLeft) - 1;
if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
// vertical:
GpiMove(hps, &ptl1);
else
GpiLine(hps, &ptl1);
GpiSetColor(hps,
WinQuerySysColor(HWND_DESKTOP,
SYSCLR_BUTTONDARK,
0));
// draw right border (to bottom)
ptl1.y = 0;
if (pData->sbcd.ulCreateFlags & SBCF_VERTICAL)
// vertical:
GpiLine(hps, &ptl1);
else
GpiMove(hps, &ptl1);
if (!(pData->sbcd.ulCreateFlags & SBCF_VERTICAL))
{
// horizontal:
// draw bottom border
ptl1.x = 0;
GpiLine(hps, &ptl1);
}
}
WinEndPaint(hps);
}
/*
*@@ ctl_fnwpSplitBar:
* window procedure for all split bars, horizontal and vertical.
* This paints the split bar and handles dragging the split bar
* and repositioning the "linked" windows afterwards.
*
* This is not a stand-alone window procedure, but must only
* be used with ctlCreateSplitWindow, which creates and subclasses
* a static control as necessary.
*
* See ctlCreateSplitWindow for more info and a detailed
* window hierarchy.
*
*@@added V0.9.0 [umoeller]
*@@changed V0.9.1 (99-12-07): fixed memory leak
*@@changed V0.9.9 (2001-02-01) [lafaix]: added MB2 drag
*@@changed V0.9.14 (2001-08-21) [umoeller]: SBCF_MOVEABLE was always ignored, fixed
*/
MRESULT EXPENTRY ctl_fnwpSplitBar(HWND hwndBar, ULONG msg, MPARAM mp1, MPARAM mp2)
{
PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndBar, QWL_USER);
PFNWP OldStaticProc = NULL;
MRESULT mrc = NULL;
if (pData)
{
OldStaticProc = pData->OldStaticProc;
switch(msg)
{
/*
* WM_MOUSEMOVE:
* change mouse pointer when over split bar.
*/
case WM_MOUSEMOVE:
if (pData->sbcd.ulCreateFlags & SBCF_MOVEABLE)
// V0.9.14 (2001-08-21) [umoeller]
// split bar is moveable:
pData->hptrOld = WinSetPointer(HWND_DESKTOP, pData->hptrMove);
else
mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
break;
/*
* WM_BUTTON1DOWN:
* this will start moving the split bar.
* We use WinTrackRect for this.
*/
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
if (pData->sbcd.ulCreateFlags & SBCF_MOVEABLE)
// V0.9.14 (2001-08-21) [umoeller]
// split bar is moveable:
TrackSplitBar(hwndBar, pData);
else
mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
break;
/*
* WM_PAINT:
* paint the split bar
*/
case WM_PAINT:
PaintSplitBar(hwndBar, pData);
break;
case WM_DESTROY:
free (pData); // added V0.9.1 (99-12-07)
mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
break;
default:
mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
}
}
return mrc;
}
/*
*@@ ctlCreateSplitWindow:
* this creates a new split window view according to
* the given SPLITBARCDATA structure. A split view
* links two existing windows together with a split
* bar in between, which can be moved with the mouse.
*
* Split windows are used for example in XWorkplace
* for the WPS class list object and in WarpIN for
* the database.
*
* After the split view has been created using this
* function, all window resizing/positioning is
* automatically performed, that is:
*
* a) if the parent window of the split view (e.g.
* the frame) is resized, the subwindows are
* adjusted;
*
* b) if the split bar is moved, the linked windows
* are adjusted also.
*
* <B>Creating a split view</B>
*
* To create a split view, you need to perform the
* following steps:
*
* 1) Create two windows that shall be separated by
* a split bar. These can be _any_ PM windows:
* a simple control window (e.g. a container),
* a frame you have created, or even a dialog
* which has been loaded using WinLoadDlg.
*
* Note: With frame windows, make sure they have the
* FCF_NOBYTEALIGN flag set, or they'll look funny.
*
* 2) Fill a SPLITBARCDATA structure with the necessary
* data for the split view (see comctl.h for details).
*
* 3) Call this function with that structure, which creates
* and returns the "split window", the invisible parent
* of the windows to be split.
* See the window hierarchy below.
*
* 4) Send a SPLM_SETLINKS message to the split window
* (returned by this function), with the two windows
* to be linked in mp1 and mp2. This has been implemented
* using a message so that you can re-link windows later
* at any time. (This is how the XWorkplace "WPS Class List"
* window does it when the settings notebook is changed.)
*
* Sending this message will change parentship (not ownership)
* of those two windows to the invisible split window.
*
* 5) Position the split window (which is returned from this
* function) within your existing windows using
* WinSetWindowPos(..., SWP_SIZE), which will automatically
* reposition the two linked subwindows of the split window.
* This works because the window procedure of the split
* window (ctl_fnwpSplitWindow) handles WM_WINDOWPOSCHANGED to
* recalculate the positions of the child windows.
*
* This function returns the HWND of the "split window".
* The handle of the split _bar_, if you absolutely need it,
* can be found using
+ WinWindowFromID(hwndWhatThisReturns, ID_SPLITBAR).
*
* After SPLM_SETLINKS, the following window hierarchy
* is established (parentship):
*
+ SPLITBARCDATA.hwndClient (whatever you have specified;
+ | e.g. FID_CLIENT of your frame window.
+ | You must intercept WM_SIZE and
+ | call WinSetWindowPos on the "split window".)
+ |
+ +-- hwndReturn ("split window" created and returned by this
+ | function; uses ctl_fnwpSplitWindow)
+ |
+ +-- hwndLink1 with SPLM_SETLINKS (parent changed)
+ | |
+ | +-- ... (your child windows remain untouched)
+ |
+ +-- ID_SPLITBAR (uses ctl_fnwpSplitBar)
+ |
+ +-- hwndLink2 with SPLM_SETLINKS (parent changed)
+ |
+ +-- ... (your child windows remain untouched)
*
* Note that only parentship of hwndSplit1 and hwndSplit2
* is changed. Ownership remains untouched. So you can specify
* any window as the owner of hwndLink1/2 so that messages
* can be forwarded properly.
*
* After the above hierarchy has been established, there are
* two situations where the "linked" windows will be repositioned
* and/or resized:
*
* 1) ctl_fnwpSplitBar will automatically resize and reposition
* the left and right "linked" windows if the user moves the
* split bar.
*
* 2) If the "split window" itself receives WM_WINDOWPOSCHANGED,
* e.g. because WinSetWindowPos has been invoked on the
* split window (which you should do when WM_SIZE is received
* by your parent window), the "linked" windows will
* automatically be repositioned and resized. This is done
* in ctl_fnwpSplitWindow.
*
* As a result, you must implement the following in your window
* procedures for the windows passed to this function:
*
* 1) The window procedure of SPLITBARCDATA.hwndClient (the
* parent of the split window) must intercept WM_SIZE and
* do a WinSetWindowPos on the split window. This will
* readjust the split bar and SPLITBARCDATA.hwndLink1/2.
*
* 2) The two linked windows should in turn handle WM_SIZE
* correctly because whenever the split window is resized,
* it invokes a WinSetWindowPos on SPLITBARCDATA.hwndLink1/2
* in turn.
*
* If you're using a single standard control as your subwindow
* (e.g. a container), this is no problem. However, if you
* specify frame windows, you might want to reposition
* the controls in those windows in turn.
*
* Note that dialog windows do not receive WM_SIZE;
* you'll need to handle WM_WINDOWPOSCHANGED instead.
*
* 3) Your window procedure should forward WM_SYSCOMMAND to
* the owner (top) window so that Alt-F4 etc. hotkeys
* still work.
*
* If you wish to <B>nest split windows,</B> you can do so by
* specifying the "split window" (the HWND which is returned
* by this function) as the "hwndLink1/2" to another call
* of this function. This way you can create a complex
* split window hierarchy (similar to what Netscape does
* with the FRAMESET tag). So to create a split view like
* this:
*
+ +---------+------------+
+ | | |
+ | | 2 |
+ | | |
+ | 1 +------------+
+ | | |
+ | | 3 |
+ | | |
+ +---------+------------+
*
* First invoke ctlCreateSplitWindow to link "2" and "3"
* together (creating a horizontal split bar), which returns
* a "split window"; then link "1" and that split window
* together again.
*
*@@added V0.9.0 [umoeller]
*/
HWND ctlCreateSplitWindow(HAB hab,
PSPLITBARCDATA psbcd) // in: split window control data
{
HWND hwndSplit = NULLHANDLE,
hwndBar = NULLHANDLE;
static s_Registered = FALSE;
if (psbcd)
{
// register "split window" class
if (!s_Registered)
{
WinRegisterClass(hab,
WC_SPLITWINDOW,
ctl_fnwpSplitWindow,
CS_SIZEREDRAW | CS_SYNCPAINT,
0); // additional bytes to reserve
s_Registered = TRUE;
}
if ( (hwndSplit = WinCreateWindow(psbcd->hwndParentAndOwner, // parent
WC_SPLITWINDOW,
"",
WS_VISIBLE,
0, 0, 10, 10,
psbcd->hwndParentAndOwner, // owner
HWND_TOP,
psbcd->ulSplitWindowID,
NULL,
NULL))
&& (hwndBar = WinCreateWindow(psbcd->hwndParentAndOwner, // parent
WC_STATIC,
"",
WS_VISIBLE // wnd style
| SS_TEXT,
0, 0, 10, 10,
psbcd->hwndParentAndOwner, // owner
HWND_TOP,
ID_SPLITBAR, // win ID
NULL, // cdata
NULL)) // presparams
)
{
// create SPLITBARDATA to store in split bar's QWL_USER
PSPLITBARDATA pData;
if (pData = (PSPLITBARDATA)malloc(sizeof(SPLITBARDATA)))
{
// set parent for split bar
WinSetParent(hwndBar, hwndSplit, FALSE);
memset(pData, 0, sizeof(SPLITBARDATA));
// copy control data
memcpy(&(pData->sbcd), psbcd, sizeof(SPLITBARCDATA));
// set other data
/* WinQueryWindowRect(hwndBar, &(pData->rclBar));
(pData->rclBar.xRight)--;
(pData->rclBar.yTop)--; */
// subclass static control to make it a split bar
pData->OldStaticProc = WinSubclassWindow(hwndBar, ctl_fnwpSplitBar);
pData->hptrOld = NULLHANDLE;
pData->hptrMove = WinQuerySysPointer(HWND_DESKTOP,
(psbcd->ulCreateFlags & SBCF_HORIZONTAL)
? SPTR_SIZENS
: SPTR_SIZEWE,
FALSE); // don't make copy
pData->fCaptured = FALSE;
pData->hwndLinked1 =
pData->hwndLinked2 = NULLHANDLE;
WinSetWindowULong(hwndBar, QWL_USER, (ULONG)pData);
}
}
}
return hwndSplit;
}
/*
*@@ ctlUpdateSplitWindow:
* this function takes a split window as input and
* repositions all its children (the split bars
* and the other subwindows which are separated by the
* split bars) according to the parent.
*
* This function gets called from ctl_fnwpSplitWindow
* when WM_SIZE is received. Normally, you won't have
* to call this function independently; you should do
* a WinSetWindowPos on the split window instead.
*
*@@added V0.9.0 [umoeller]
*/
BOOL ctlUpdateSplitWindow(HWND hwndSplit)
{
BOOL brc = FALSE;
HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR);
if (hwndSplitBar)
{
PSPLITBARDATA psbd = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER);
if (psbd)
{
PSPLITBARCDATA psbcd = &(psbd->sbcd);
RECTL rclSplit,
rclBar;
ULONG ul3DOfs = 0;
// _Pmpf(("Entering ctlUpdateSplitWindow for hwndSplit 0x%lX", hwndSplit));
// query the rectangle of the split window's parent;
// this is either the client or another split window
WinQueryWindowRect(hwndSplit, &rclSplit);
/* _Pmpf((" rect: %d, %d, %d, %d",
rclSplit.xLeft,
rclSplit.yBottom,
rclSplit.xRight - rclSplit.xLeft,
rclSplit.yTop - rclSplit.yBottom)); */
// set anti-recursion flag;
// this is neccessary, because ctl_fnwpSplitWindow
// calls this func again when
// WM_WINDOWPOSCHANGED comes in
// psbd->fNoAdjust = TRUE;
// set split window to the same
/* WinSetWindowPos(hwndSplit, HWND_TOP,
rclSplit.xLeft,
rclSplit.yBottom,
rclSplit.xRight - rclSplit.xLeft,
rclSplit.yTop - rclSplit.yBottom,
SWP_MOVE | SWP_SIZE); */
// psbd->fNoAdjust = FALSE;
// update split bar
if (psbcd->ulCreateFlags & SBCF_HORIZONTAL)
{
// _Pmpf((" Calc horizontal"));
// horizontal split bar:
if (psbcd->ulCreateFlags & SBCF_PERCENTAGE)
// take height of client and apply percentage
rclBar.yBottom = (rclSplit.yTop - rclSplit.yBottom)
* psbcd->lPos
/ 100;
else
if (psbcd->lPos > 0)
// offset from bottom:
rclBar.yBottom = psbcd->lPos;
else
// offset from right:
rclBar.yBottom = (rclSplit.yTop - rclSplit.yBottom)
+ psbcd->lPos; // which is negative
rclBar.yTop = rclBar.yBottom + WinQuerySysValue(HWND_DESKTOP,
SV_CXSIZEBORDER);
rclBar.xLeft = 0;
// take width of client
rclBar.xRight = (rclSplit.xRight - rclSplit.xLeft);
}
else
{
// _Pmpf((" Calc vertical"));
// vertical split bar:
if (psbcd->ulCreateFlags & SBCF_PERCENTAGE)
// take width of client and apply percentage
rclBar.xLeft = (rclSplit.xRight - rclSplit.xLeft)
* psbcd->lPos
/ 100;
else
if (psbcd->lPos > 0)
// offset from left:
rclBar.xLeft = psbcd->lPos;
else
// offset from right:
rclBar.xLeft = (rclSplit.xRight - rclSplit.xLeft)
+ psbcd->lPos; // which is negative
rclBar.xRight = rclBar.xLeft + WinQuerySysValue(HWND_DESKTOP,
SV_CXSIZEBORDER);
rclBar.yBottom = 0;
// take height of client
rclBar.yTop = (rclSplit.yTop - rclSplit.yBottom);
}
// reposition split bar
brc = WinSetWindowPos(hwndSplitBar,
HWND_TOP,
rclBar.xLeft,
rclBar.yBottom,
rclBar.xRight - rclBar.xLeft,
rclBar.yTop - rclBar.yBottom,
SWP_MOVE | SWP_SIZE);
/* _Pmpf((" Set splitbar hwnd %lX to %d, %d, %d, %d; rc: %d",
hwndSplitBar,
rclBar.xLeft,
rclBar.yBottom,
rclBar.xRight - rclBar.xLeft,
rclBar.yTop - rclBar.yBottom,
brc)); */
// reposition left/bottom window of split bar
if (psbcd->ulCreateFlags & SBCF_3DSUNK)
ul3DOfs = 1;
// else 0
// now reposition the linked windows
if (psbcd->ulCreateFlags & SBCF_HORIZONTAL)
{
// horizontal:
// reposition bottom window of split bar
WinSetWindowPos(psbd->hwndLinked1,
HWND_TOP,
ul3DOfs,
ul3DOfs,
rclBar.xRight - rclBar.xLeft - ul3DOfs*2,
rclBar.yBottom - ul3DOfs*2, // the window rect is non-inclusive
SWP_MOVE | SWP_SIZE);
// reposition top window of split bar
WinSetWindowPos(psbd->hwndLinked2,
HWND_TOP,
ul3DOfs,
rclBar.yTop + ul3DOfs, // the window rect is non-inclusive
rclBar.xRight - rclBar.xLeft - ul3DOfs*2,
rclSplit.yTop - rclBar.yTop - ul3DOfs*2,
SWP_MOVE | SWP_SIZE);
}
else
{
// vertical:
// reposition left window of split bar
WinSetWindowPos(psbd->hwndLinked1,
HWND_TOP,
ul3DOfs,
ul3DOfs,
rclBar.xLeft - ul3DOfs*2, // the window rect is non-inclusive
rclBar.yTop - rclBar.yBottom - ul3DOfs*2,
SWP_MOVE | SWP_SIZE);
// reposition right window of split bar
WinSetWindowPos(psbd->hwndLinked2,
HWND_TOP,
rclBar.xRight + ul3DOfs, // the window rect is non-inclusive
ul3DOfs,
rclSplit.xRight - rclBar.xRight - ul3DOfs*2,
rclBar.yTop - rclBar.yBottom - ul3DOfs*2,
SWP_MOVE | SWP_SIZE);
}
// repaint split window (3D frame)
WinInvalidateRect(hwndSplit,
NULL, // all
FALSE); // don't repaint children
}
}
return brc;
}
/*
*@@ ctlQuerySplitPos:
* this returns the position of the split bar
* (the child control of hwndSplit; see ctlCreateSplitWindow
* for the window hierarchy).
*
* The meaning of the return value depends on what you
* specified with ulCreateFlags in the SPLITBARCDATA
* structure passed to ctlCreateSplitWindow, that is,
* it can be a percentage or an offset from the left
* or from the right of the split window.
*
* This returns NULL upon errors.
*
*@@added V0.9.0 [umoeller]
*/
LONG ctlQuerySplitPos(HWND hwndSplit)
{
// the split bar data is stored in QWL_USER of the
// split bar (not the split window)
HWND hwndSplitBar;
PSPLITBARDATA psbd;
if ( (hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR))
&& (psbd = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER))
)
return psbd->sbcd.lPos;
return 0;
}