/* *@@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-2006 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 #include #include #include #include // needed for except.h #include // 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] *@@changed V1.0.0 (2002-08-24) [umoeller]: added SBCF_3DEXPLORERSTYLE */ STATIC VOID PaintSplitWindow(HWND hwndSplit) { HPS hps; if (hps = WinBeginPaint(hwndSplit, (HPS)0, NULL)) { HWND hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR); PSPLITBARDATA pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER); if ((pData->hwndLinked1) && (pData->hwndLinked2)) { SWP swp; // switch to RGB mode gpihSwitchToRGB(hps); // "3D-sunk" style? if (pData->sbcd.ulCreateFlags & SBCF_3DEXPLORERSTYLE) { // this style is new with V1.0.0 (2002-08-24) [umoeller]; // simulate the Warp 4 entry field margins around the // right control only, but leave the left control flat. RECTL rcl; WinQueryWindowPos(pData->hwndLinked2, &swp); rcl.xLeft = swp.x - 2; rcl.yBottom = swp.y - 2; rcl.xRight = swp.x + swp.cx + 1; rcl.yTop = swp.y + swp.cy + 1; gpihDraw3DFrame2(hps, &rcl, 1, RGBCOL_BLACK, pData->lcol3DLight); gpihDraw3DFrame2(hps, &rcl, 1, RGBCOL_BLACK, pData->lcolInactiveBorder); } else if (pData->sbcd.ulCreateFlags & SBCF_3DSUNK) { // yes: draw sunk frame around split windows POINTL ptl1; WinQueryWindowPos(pData->hwndLinked1, &swp); GpiSetColor(hps, pData->lcol3DDark); 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, pData->lcol3DLight); ptl1.y = swp.y - 1; GpiLine(hps, &ptl1); ptl1.x = swp.x - 1; GpiLine(hps, &ptl1); WinQueryWindowPos(pData->hwndLinked2, &swp); GpiSetColor(hps, pData->lcol3DDark); 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, pData->lcol3DLight); 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) if (((PSWP)mp1)->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; if (pData = (PSPLITBARDATA)WinQueryWindowULong(hwndSplitBar, QWL_USER)) { 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] *@@changed XWP V1.0.5 (2006-04-13) [pr]: Fix horrid rounding errors */ 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); // XWP V1.0.5 (2006-04-13) [pr]: Fix horrid rounding errors pData->sbcd.lPos = (ulNewYPos * 200 + (rclClient.yTop - rclClient.yBottom)) / ((rclClient.yTop - rclClient.yBottom) * 2); } 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); // XWP V1.0.5 (2006-04-13) [pr]: Fix horrid rounding errors pData->sbcd.lPos = (ulNewXPos * 200 + (rclClient.xRight - rclClient.xLeft)) / ((rclClient.xRight - rclClient.xLeft) * 2); } 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; if (hps = WinBeginPaint(hwndBar, NULLHANDLE, &rcl)) { WinQueryWindowRect(hwndBar, &rclBar); // switch to RGB mode GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL); WinFillRect(hps, &rclBar, pData->lcolInactiveBorder); if (!(pData->sbcd.ulCreateFlags & (SBCF_3DSUNK | SBCF_3DEXPLORERSTYLE))) // V1.0.0 (2002-08-31) [umoeller] { GpiSetColor(hps, pData->lcol3DLight); // 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, pData->lcol3DDark); // 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. * * Creating a split view * * 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 nest split windows, 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)); // 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; // caching these colors now V1.0.0 (2002-08-21) [umoeller] pData->lcol3DDark = WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0); pData->lcol3DLight = WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0); pData->lcolInactiveBorder = WinQuerySysColor(HWND_DESKTOP, SYSCLR_INACTIVEBORDER, 0); 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] *@@changed V1.0.0 (2002-08-24) [umoeller]: added support for SBCF_3DEXPLORERSTYLE *@@changed XWP V1.0.5 (2006-04-13) [pr]: Fix rounding errors and repaint problems @@fixes 228 */ BOOL ctlUpdateSplitWindow(HWND hwndSplit) { BOOL brc = FALSE; HWND hwndSplitBar; PSPLITBARDATA psbd; if ( (hwndSplitBar = WinWindowFromID(hwndSplit, ID_SPLITBAR)) && (psbd = (PSPLITBARDATA)WinQueryWindowPtr(hwndSplitBar, QWL_USER)) ) { PSPLITBARCDATA psbcd = &(psbd->sbcd); RECTL rclSplit, rclBar; LONG l3DOfsLink1 = 0, l3DOfsLink2 = 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)); */ // 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 // XWP V1.0.5 (2006-04-13) [pr]: Fix horrid rounding errors rclBar.yBottom = ((rclSplit.yTop - rclSplit.yBottom) * psbcd->lPos + 50) / 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 // XWP V1.0.5 (2006-04-13) [pr]: Fix horrid rounding errors rclBar.xLeft = ((rclSplit.xRight - rclSplit.xLeft) * psbcd->lPos + 50) / 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_3DEXPLORERSTYLE) { l3DOfsLink2 = 2; } else if (psbcd->ulCreateFlags & SBCF_3DSUNK) { l3DOfsLink1 = 1; l3DOfsLink2 = 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, l3DOfsLink1, l3DOfsLink1, rclBar.xRight - rclBar.xLeft - 2 * l3DOfsLink1, rclBar.yBottom - 2 * l3DOfsLink1, // the window rect is non-inclusive SWP_MOVE | SWP_SIZE); // reposition top window of split bar WinSetWindowPos(psbd->hwndLinked2, HWND_TOP, l3DOfsLink2, rclBar.yTop + l3DOfsLink2, // the window rect is non-inclusive rclBar.xRight - rclBar.xLeft - 2 * l3DOfsLink2, rclSplit.yTop - rclBar.yTop - 2 * l3DOfsLink2, SWP_MOVE | SWP_SIZE); } else { // vertical: // reposition left window of split bar WinSetWindowPos(psbd->hwndLinked1, HWND_TOP, l3DOfsLink1, l3DOfsLink1, rclBar.xLeft - 2 * l3DOfsLink1, // the window rect is non-inclusive rclBar.yTop - rclBar.yBottom - 2 * l3DOfsLink1, SWP_MOVE | SWP_SIZE); // reposition right window of split bar WinSetWindowPos(psbd->hwndLinked2, HWND_TOP, rclBar.xRight + l3DOfsLink2, // the window rect is non-inclusive l3DOfsLink2, rclSplit.xRight - rclBar.xRight - 2 * l3DOfsLink2, rclBar.yTop - rclBar.yBottom - 2 * l3DOfsLink2, SWP_MOVE | SWP_SIZE); } // repaint split window (3D frame) WinInvalidateRect(hwndSplit, NULL, // all FALSE); // don't repaint children // XWP V1.0.5 (2006-04-13) [pr]: repaint right/bottom frame @@fixes 228 WinInvalidateRect(psbd->hwndLinked2, NULL, TRUE); } 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; }