/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code 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, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code 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. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "tools/edit_gui_common.h" #include "../../sys/win32/win_local.h" #include "RollupPanel.h" // Based on original code by Johann Nadalutti #define RP_PGBUTTONHEIGHT 18 #define RP_SCROLLBARWIDTH 6 #define RP_GRPBOXINDENT 6 #define RP_SCROLLBARCOLOR RGB(150,180,180) #define RP_ROLLCURSOR MAKEINTRESOURCE(32649) // see IDC_HAND (WINVER >= 0x0500) //Popup Menu Ids #define RP_IDM_EXPANDALL 0x100 #define RP_IDM_COLLAPSEALL 0x101 #define RP_IDM_STARTITEMS 0x102 idList rvRollupPanel::mDialogs; HHOOK rvRollupPanel::mDialogHook = NULL; #define DEFERPOS /* ================ rvRollupPanel::rvRollupPanel constructor ================ */ rvRollupPanel::rvRollupPanel ( void ) { mStartYPos = 0; mItemHeight = 0; mWindow = NULL; } /* ================ rvRollupPanel::~rvRollupPanel destructor ================ */ rvRollupPanel::~rvRollupPanel ( void ) { // destroy the items for ( ; mItems.Num(); ) { _RemoveItem ( 0 ); } } /* ================ rvRollupPanel::Create Create the rollup panel window ================ */ bool rvRollupPanel::Create ( DWORD dwStyle, const RECT& rect, HWND parent, unsigned int id ) { WNDCLASSEX wndClass; memset ( &wndClass, 0, sizeof(wndClass) ); wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.lpszClassName = "ROLLUP_PANEL"; wndClass.lpfnWndProc = WindowProc; wndClass.hbrBackground = (HBRUSH)GetSysColorBrush ( COLOR_3DFACE ); wndClass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wndClass.lpszMenuName = NULL; wndClass.hInstance = win32.hInstance; wndClass.style = CS_VREDRAW | CS_HREDRAW; RegisterClassEx ( &wndClass ); mWindow = CreateWindowEx ( WS_EX_TOOLWINDOW, "ROLLUP_PANEL", "", dwStyle|WS_CLIPSIBLINGS, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, parent, NULL, win32.hInstance, this ); if ( !mWindow ) { return false; } return true; } /* ================ rvRollupPanel::InsertItem Insert and item into the rollup panel. Return -1 if an error occured ================ */ int rvRollupPanel::InsertItem ( const char* caption, HWND dialog, bool autoDestroy, int index ) { assert ( caption ); assert ( dialog ); // -1 means add to the end if ( index > 0 && index >= mItems.Num() ) { index = -1; } // Get client rect RECT r; GetClientRect(mWindow,&r); // Create the GroupBox control HWND groupbox = CreateWindow ( "BUTTON", "", WS_CHILD|BS_GROUPBOX, r.left, r.top, r.right-r.left, r.bottom-r.top, mWindow, 0, win32.hInstance, NULL ); // Create the expand button HWND button = CreateWindow ( "BUTTON", caption, WS_CHILD|BS_AUTOCHECKBOX|BS_PUSHLIKE|BS_FLAT, r.left, r.top, r.right-r.left, r.bottom-r.top, mWindow, 0, win32.hInstance, NULL ); // Change the button's font SendMessage ( button, WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0 ); // Add item to the item list RPITEM* item = new RPITEM; item->mExpanded = false; item->mEnable = true; item->mDialog = dialog; item->mButton = button; item->mGroupBox = groupbox; item->mOldDlgProc = (WNDPROC) GetWindowLongPtr ( dialog, DWLP_DLGPROC ); item->mOldButtonProc = (WNDPROC) GetWindowLongPtr ( button, GWLP_WNDPROC ); item->mAutoDestroy = autoDestroy; strcpy ( item->mCaption, caption ); if ( index < 0 ) { index = mItems.Append ( item ); } else { mItems.Insert ( item, index ); } // Store data with the dialog window in its user data SetWindowLongPtr ( dialog, GWLP_USERDATA, (LONG_PTR)item ); // Attach item to button through user data SetWindowLongPtr( button, GWLP_USERDATA, (LONG_PTR)item ); SetWindowLongPtr( button, GWL_ID, index ); // Subclass dialog SetWindowLongPtr( dialog, DWLP_DLGPROC, (LONG_PTR)DialogProc ); // SubClass button SetWindowLongPtr( button, GWLP_WNDPROC, (LONG_PTR)ButtonProc ); // Update mItemHeight += RP_PGBUTTONHEIGHT+(RP_GRPBOXINDENT/2); RecallLayout ( ); // One hook for all panel dialogs if ( !mDialogHook ) { mDialogHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId() ); } mDialogs.Append ( dialog ); return index; } /* ================ rvRollupPanel::RemoveItem Remove the item at the given index from the rollup panel ================ */ void rvRollupPanel::RemoveItem ( int index ) { // safety check if ( index >= mItems.Num() || index < 0 ) { return; } // remove the item _RemoveItem( index ); // update the layout RecallLayout ( ); } /* ================ rvRollupPanel::RemoveAllItems Remove all items from the control ================ */ void rvRollupPanel::RemoveAllItems() { for ( ; mItems.Num(); ) { _RemoveItem ( 0 ); } // update layout RecallLayout ( ); } /* ================ rvRollupPanel::_RemoveItem called by RemoveItem and RemoveAllItems methods to acutally remove the item ================ */ void rvRollupPanel::_RemoveItem ( int index ) { RPITEM* item = mItems[index]; // get the item rect RECT ir; GetWindowRect ( item->mDialog, &ir ); // update item height mItemHeight -= RP_PGBUTTONHEIGHT+(RP_GRPBOXINDENT/2); if ( item->mExpanded ) { mItemHeight -= (ir.bottom-ir.top); } // destroy windows if ( item->mButton ) { DestroyWindow ( item->mButton ); } if ( item->mGroupBox ) { DestroyWindow ( item->mGroupBox ); } if ( item->mDialog && item->mAutoDestroy ) { DestroyWindow ( item->mDialog ); mDialogs.Remove ( item->mDialog ); } if ( mDialogs.Num () <= 0 ) { UnhookWindowsHookEx( mDialogHook ); mDialogHook = NULL; } // finish up mItems.RemoveIndex ( index ); delete item; } /* ================ rvRollupPanel::ExpandItem expand or collapse the item at the given index ================ */ void rvRollupPanel::ExpandItem( int index, bool expand ) { // safety check if ( index >= mItems.Num() || index < 0 ) { return; } _ExpandItem ( mItems[index], expand ); RecallLayout ( ); // scroll to this page (automatic page visibility) if ( expand ) { ScrollToItem ( index, false ); } } /* ================ rvRollupPanel::ExpandItem expand or collapse the item at the given index ================ */ void rvRollupPanel::ExpandAllItems( bool expand ) { int i; // expand all items for ( i=0; i < mItems.Num(); i ++ ) { _ExpandItem ( mItems[i], expand ); } RecallLayout(); } /* ================ rvRollupPanel::ExpandItem expand or collapse the item at the given index ================ */ void rvRollupPanel::_ExpandItem ( RPITEM* item, bool expand ) { // check if we need to change state if ( item->mExpanded == expand || !item->mEnable ) { return; } RECT ir; GetWindowRect ( item->mDialog, &ir ); // Expand-collapse item->mExpanded = expand; if ( expand ) { mItemHeight += (ir.bottom - ir.top); } else { mItemHeight -= (ir.bottom - ir.top); } } /* ================ rvRollupPanel::EnableItem enable/disable the item at the given index ================ */ void rvRollupPanel::EnableItem ( int index, bool enable ) { // safety check if ( index >= mItems.Num() || index < 0 ) { return; } _EnableItem ( mItems[index], enable ); RecallLayout ( ); } /* ================ rvRollupPanel::EnableAllItems enable/disable all items in the panel ================ */ void rvRollupPanel::EnableAllItems ( bool enable ) { int i; for ( i=0; i < mItems.Num(); i++ ) { _EnableItem ( mItems[i], enable ); } RecallLayout ( ); } /* ================ rvRollupPanel::_EnableItem Called by EnableItem and EnableAllItems to do the work of enabling/disablgin the window ================ */ void rvRollupPanel::_EnableItem ( RPITEM* item, bool enable ) { // check if we need to change state if ( item->mEnable == enable ) { return; } RECT ir; GetWindowRect ( item->mDialog, &ir ); item->mEnable = enable; if ( item->mExpanded ) { mItemHeight -= (ir.bottom-ir.top); item->mExpanded = false; } } /* ================ rvRollupPanel::ScrollToItem Scroll a page at the top of the Rollup Panel if top = true or just ensure item visibility into view if top = false ================ */ void rvRollupPanel::ScrollToItem ( int index, bool top ) { // safety check if ( index >= mItems.Num() || index < 0 ) { return; } RPITEM* item = mItems[index]; // get rects RECT r; RECT ir; GetWindowRect ( mWindow, &r ); GetWindowRect ( item->mDialog, &ir ); // check page visibility if ( top || ((ir.bottom > r.bottom) || (ir.top < r.top))) { // compute new mStartYPos GetWindowRect( item->mButton, &ir ); mStartYPos -= (ir.top-r.top); RecallLayout(); } } /* ================ rvRollupPanel::MoveItemAt newIndex can be equal to -1 (move at end) return -1 if an error occurs ================ */ int rvRollupPanel::MoveItemAt ( int index, int newIndex ) { if ( index == newIndex || index >= mItems.Num() || index < 0 ) { return -1; } // remove page from its old position RPITEM* item = mItems[index]; mItems.RemoveIndex ( index ); // insert at its new position if ( newIndex < 0 ) { index = mItems.Append( item ); } else { mItems.Insert ( item, newIndex ); index = newIndex; } RecallLayout ( ); return index; } /* ================ rvRollupPanel::RecallLayout Update the layout of the control based on current states ================ */ void rvRollupPanel::RecallLayout ( void ) { int bottomPagePos; RECT r; int posy; int i; // check StartPosY GetClientRect ( mWindow, &r ); bottomPagePos = mStartYPos + mItemHeight; if ( bottomPagePos < r.bottom-r.top ) { mStartYPos = (r.bottom-r.top) - mItemHeight; } if ( mStartYPos > 0 ) { mStartYPos = 0; } // update layout #ifdef DEFERPOS HDWP hdwp; hdwp = BeginDeferWindowPos ( mItems.Num() * 3 ); #endif posy = mStartYPos; for ( i=0; i < mItems.Num(); i++ ) { RPITEM* item = mItems[i]; // enable / disable button SendMessage ( item->mButton, BM_SETCHECK, (item->mEnable&item->mExpanded)?BST_CHECKED:BST_UNCHECKED, 0 ); EnableWindow ( item->mButton, item->mEnable ); // Expanded if ( item->mExpanded && item->mEnable ) { RECT ir; GetWindowRect ( item->mDialog, &ir ); // update GroupBox position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mGroupBox, 0, 2, posy, (r.right-r.left)-3-RP_SCROLLBARWIDTH, (ir.bottom-ir.top)+RP_PGBUTTONHEIGHT+RP_GRPBOXINDENT-4, SWP_NOZORDER|SWP_SHOWWINDOW); //Update Dialog position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mDialog, 0, RP_GRPBOXINDENT, posy+RP_PGBUTTONHEIGHT, (r.right-r.left)-RP_SCROLLBARWIDTH-(RP_GRPBOXINDENT*2), ir.bottom-ir.top, SWP_NOZORDER|SWP_SHOWWINDOW); //Update Button's position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mButton, 0, RP_GRPBOXINDENT, posy, (r.right-r.left)-RP_SCROLLBARWIDTH-(RP_GRPBOXINDENT*2), RP_PGBUTTONHEIGHT, SWP_NOZORDER|SWP_SHOWWINDOW); posy += (ir.bottom-ir.top) + RP_PGBUTTONHEIGHT; } // collapsed else { // update GroupBox position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mGroupBox, 0, 2, posy, (r.right-r.left)-3-RP_SCROLLBARWIDTH, 16, SWP_NOZORDER|SWP_SHOWWINDOW); // update Dialog position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mDialog, 0, RP_GRPBOXINDENT, 0, 0, 0,SWP_NOZORDER|SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE); // update Button's position and size #ifdef DEFERPOS DeferWindowPos ( hdwp, #else SetWindowPos ( #endif item->mButton, 0, RP_GRPBOXINDENT, posy, (r.right-r.left)-RP_SCROLLBARWIDTH-(RP_GRPBOXINDENT*2), RP_PGBUTTONHEIGHT, SWP_NOZORDER|SWP_SHOWWINDOW); posy += RP_PGBUTTONHEIGHT; } posy += (RP_GRPBOXINDENT/2); } #ifdef DEFERPOS EndDeferWindowPos ( hdwp ); #endif // update Scroll Bar RECT br; SetRect ( &br, r.right-RP_SCROLLBARWIDTH,r.top,r.right,r.bottom); InvalidateRect( mWindow, &br, FALSE ); UpdateWindow ( mWindow ); } /* ================ rvRollupPanel::GetItemIndex Return -1 if no matching item was found, otherwise the index of the item ================ */ int rvRollupPanel::GetItemIndex ( HWND wnd ) { int i; //Search matching button's hwnd for ( i=0; i < mItems.Num(); i++ ) { if ( wnd == mItems[i]->mButton ) { return i; } } return -1; } int rvRollupPanel::GetItemIndex ( const char* caption ) { int i; //Search matching button's hwnd for ( i=0; i < mItems.Num(); i++ ) { if ( !idStr::Icmp ( caption, mItems[i]->mCaption ) ) { return i; } } return -1; } /* ================ rvRollupPanel::GetItem Return NULL if the index is invalid ================ */ RPITEM* rvRollupPanel::GetItem ( int index ) { // safety check if ( index >= mItems.Num() || index < 0 ) { return NULL; } return mItems[index]; } /* ================ rvRollupPanel::DialogProc Dialog procedure for items ================ */ LRESULT CALLBACK rvRollupPanel::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { RPITEM* item = (RPITEM*)GetWindowLongPtr ( hWnd, GWLP_USERDATA ); rvRollupPanel* _this = (rvRollupPanel*)GetWindowLongPtr( GetParent ( hWnd ), GWLP_USERDATA ); RECT r; GetClientRect ( _this->mWindow, &r ); if ( _this->mItemHeight > r.bottom-r.top ) { switch (uMsg) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: { POINT pos; GetCursorPos ( &pos ); _this->mOldMouseYPos = pos.y; ::SetCapture(hWnd); return 0; } case WM_LBUTTONUP: case WM_MBUTTONUP: { if ( ::GetCapture() == hWnd ) { ::ReleaseCapture(); return 0; } break; } case WM_MOUSEMOVE: if ( (::GetCapture() == hWnd) && (wParam==MK_LBUTTON || wParam==MK_MBUTTON)) { POINT pos; GetCursorPos(&pos); _this->mStartYPos += (pos.y-_this->mOldMouseYPos); _this->RecallLayout(); _this->mOldMouseYPos = pos.y; InvalidateRect ( _this->mWindow, NULL, TRUE ); return 0; } break; case WM_SETCURSOR: if ( (HWND)wParam == hWnd) { SetCursor ( LoadCursor (NULL, RP_ROLLCURSOR) ); return TRUE; } break; } } return ::CallWindowProc ( item->mOldDlgProc, hWnd, uMsg, wParam, lParam ); } /* ================ rvRollupPanel::DialogProc Button procedure for items ================ */ LRESULT CALLBACK rvRollupPanel::ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if ( uMsg == WM_SETFOCUS ) { return FALSE; } RPITEM* item = (RPITEM*)GetWindowLongPtr(hWnd, GWLP_USERDATA); return ::CallWindowProc( item->mOldButtonProc, hWnd, uMsg, wParam, lParam ); } /* ================ rvRollupPanel::WindowProc Window procedure for rollup panel ================ */ LRESULT CALLBACK rvRollupPanel::WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { rvRollupPanel* panel; panel = (rvRollupPanel*)GetWindowLongPtr (hWnd, GWLP_USERDATA); switch ( uMsg ) { case WM_CREATE: { LPCREATESTRUCT cs; // Attach the class to the window first cs = (LPCREATESTRUCT) lParam; panel = (rvRollupPanel*) cs->lpCreateParams; SetWindowLongPtr ( hWnd, GWLP_USERDATA, (LONG_PTR)panel ); break; } case WM_COMMAND: panel->HandleCommand ( wParam, lParam ); break; case WM_PAINT: return panel->HandlePaint ( wParam, lParam ); case WM_SIZE: return panel->HandleSize ( wParam, lParam ); case WM_LBUTTONDOWN: panel->HandleLButtonDown ( wParam, lParam ); break; case WM_LBUTTONUP: panel->HandleLButtonUp ( wParam, lParam ); break; case WM_MOUSEMOVE: panel->HandleMouseMove ( wParam, lParam ); break; case WM_MOUSEWHEEL: panel->HandleMouseWheel ( wParam, lParam ); break; case WM_MOUSEACTIVATE: panel->HandleMouseActivate ( wParam, lParam ); break; case WM_CONTEXTMENU: return panel->HandleContextMenu ( wParam, lParam ); } return DefWindowProc ( hWnd, uMsg, wParam, lParam ); } /* ================ rvRollupPanel::HandleCommand Handle the WM_COMMAND message ================ */ int rvRollupPanel::HandleCommand ( WPARAM wParam, LPARAM lParam ) { // popup menu command to expand or collapse pages if ( LOWORD(wParam) == RP_IDM_EXPANDALL ) { ExpandAllItems ( true ); } else if ( LOWORD(wParam) == RP_IDM_COLLAPSEALL ) { ExpandAllItems ( false ); } // popupMenu command to expand page else if ( LOWORD(wParam) >= RP_IDM_STARTITEMS && LOWORD(wParam) < RP_IDM_STARTITEMS + GetItemCount ( ) ) { int index = LOWORD(wParam)-RP_IDM_STARTITEMS; ExpandItem ( index, !IsItemExpanded(index) ); } // button command else if ( HIWORD(wParam) == BN_CLICKED ) { int index = GetItemIndex ((HWND)lParam); if ( index != -1 ) { ExpandItem ( index, !IsItemExpanded ( index ) ); return 0; } } return 0; } /* ================ rvRollupPanel::HandlePaint Handle the WM_PAINT message ================ */ int rvRollupPanel::HandlePaint( WPARAM wParam, LPARAM lParam ) { HDC dc; PAINTSTRUCT ps; RECT r; RECT br; int sbPos; int sbSize; int clientHeight; dc = BeginPaint ( mWindow, &ps ); // scrollbar GetClientRect ( mWindow, &r ); SetRect ( &br, r.right-RP_SCROLLBARWIDTH, r.top, r.right, r.bottom ); DrawEdge ( dc, &br, EDGE_RAISED, BF_RECT ); sbPos = 0; sbSize = 0; clientHeight = (r.bottom-r.top) - 4; if ( mItemHeight > (r.bottom-r.top) ) { sbSize = clientHeight - (((mItemHeight-(r.bottom-r.top)) * clientHeight ) / mItemHeight ); sbPos = -(mStartYPos * clientHeight) / mItemHeight; } else { sbSize = clientHeight; } br.left +=2; br.right -=1; br.top = sbPos+2; br.bottom = br.top+sbSize; HBRUSH brush; brush = CreateSolidBrush ( RP_SCROLLBARCOLOR ); FillRect ( dc, &br, brush ); DeleteObject ( brush ); SetRect ( &r, br.left,2,br.right,br.top ); FillRect ( dc, &r, (HBRUSH)GetStockObject ( BLACK_BRUSH ) ); SetRect ( &r, br.left,br.bottom,br.right,2+clientHeight ); FillRect ( dc, &r, (HBRUSH)GetStockObject ( BLACK_BRUSH ) ); return 0; } /* ================ rvRollupPanel::HandleSize Handle the WM_SIZE message ================ */ int rvRollupPanel::HandleSize ( WPARAM wParam, LPARAM lParam ) { DefWindowProc ( mWindow, WM_SIZE, wParam, lParam ); RecallLayout(); return 0; } /* ================ rvRollupPanel::HandleLButtonDown Handle the WM_LBUTTONDOWN message ================ */ int rvRollupPanel::HandleLButtonDown ( WPARAM wParam, LPARAM lParam ) { RECT r; RECT br; POINT point; GetClientRect ( mWindow, &r ); if ( mItemHeight <= r.bottom - r.top ) { return 0; } point.x = LOWORD(lParam); point.y = HIWORD(lParam); SetRect ( &br, r.right - RP_SCROLLBARWIDTH, r.top, r.right, r.bottom ); if ( (wParam & MK_LBUTTON) && PtInRect ( &br, point ) ) { SetCapture( mWindow ); int clientHeight = (r.bottom-r.top) - 4; int sbSize = clientHeight - (((mItemHeight - (r.bottom-r.top)) * clientHeight) / mItemHeight ); int sbPos = -(mStartYPos * clientHeight) / mItemHeight; // click inside scrollbar cursor if ( (point.y < (sbPos + sbSize)) && (point.y > sbPos )) { mSBOffset = sbPos - point.y + 1; } // click outside scrollbar cursor (2 cases => above or below cursor) else { int distup = point.y - sbPos; int distdown = (sbPos + sbSize) - point.y; if ( distup < distdown ) { //above mSBOffset = 0; } else { //below mSBOffset = -sbSize; } } // calc new m_nStartYPos from mouse pos int targetPos = point.y + mSBOffset; mStartYPos =- (targetPos * mItemHeight) / clientHeight; // update RecallLayout(); } return 0; } /* ================ rvRollupPanel::HandleLButtonUp Handle the WM_LBUTTONUP message ================ */ int rvRollupPanel::HandleLButtonUp ( WPARAM wParam, LPARAM lParam ) { if ( GetCapture() == mWindow ) { ReleaseCapture(); } return 0; } /* ================ rvRollupPanel::HandleMouseMove Handle the WM_MOUSEMOVE message ================ */ int rvRollupPanel::HandleMouseMove ( WPARAM wParam, LPARAM lParam ) { RECT r; RECT br; POINT point; GetClientRect ( mWindow, &r ); if ( mItemHeight <= r.bottom - r.top ) { return 0; } point.x = LOWORD(lParam); point.y = HIWORD(lParam); SetRect ( &br, r.right - RP_SCROLLBARWIDTH, r.top, r.right, r.bottom ); if ( (wParam & MK_LBUTTON) && (GetCapture() == mWindow )) { // calc new m_nStartYPos from mouse pos int clientHeight = (r.bottom-r.top) - 4; int targetPos = point.y + mSBOffset; mStartYPos =- (targetPos * mItemHeight) / clientHeight; RecallLayout ( ); InvalidateRect ( mWindow, NULL, FALSE ); // UpdateWindow ( mWindow ); } return 0; } /* ================ rvRollupPanel::HandleMouseWheel Handle the WM_MOUSEWHEEL message ================ */ int rvRollupPanel::HandleMouseWheel ( WPARAM wParam, LPARAM lParam ) { // calc new m_nStartYPos mStartYPos += (HIWORD(wParam) / 4); RecallLayout(); return 0; } /* ================ rvRollupPanel::HandleMouseActivate Handle the WM_MOUSEACTIVATE message ================ */ int rvRollupPanel::HandleMouseActivate ( WPARAM wParam, LPARAM lParam ) { SetFocus ( mWindow ); return 0; } /* ================ rvRollupPanel::HandleContextMenu Handle the WM_CONTEXTMENU message ================ */ int rvRollupPanel::HandleContextMenu ( WPARAM wParam, LPARAM lParam ) { HMENU menu; int i; POINT point; menu = CreatePopupMenu ( ); if ( !menu ) { return 0; } point.x = LOWORD(lParam); point.y = HIWORD(lParam); AppendMenu ( menu, MF_STRING, RP_IDM_EXPANDALL, "Expand all" ); AppendMenu ( menu, MF_STRING, RP_IDM_COLLAPSEALL, "Collapse all" ); AppendMenu ( menu, MF_SEPARATOR, 0, "" ); //Add all pages with checked style for expanded ones for ( i=0; i < mItems.Num(); i++ ) { char itemName[1024]; GetWindowText ( mItems[i]->mButton, itemName, 1023 ); AppendMenu ( menu, MF_STRING, RP_IDM_STARTITEMS + i, itemName ); if ( mItems[i]->mExpanded ) { CheckMenuItem ( menu, RP_IDM_STARTITEMS + i, MF_CHECKED); } TrackPopupMenu ( menu, TPM_LEFTALIGN|TPM_LEFTBUTTON, point.x, point.y, 0, mWindow, NULL ); } return 0; } /* ================ rvRollupPanel::GetMsgProc Ensures normal dialog functions work in the alpha select dialog ================ */ LRESULT FAR PASCAL rvRollupPanel::GetMsgProc ( int nCode, WPARAM wParam, LPARAM lParam ) { LPMSG lpMsg = (LPMSG) lParam; if ( nCode >= 0 && PM_REMOVE == wParam ) { // Don't translate non-input events. if ( (lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) ) { int i; for ( i = 0; i < mDialogs.Num(); i ++ ) { if ( IsDialogMessage( mDialogs[i], lpMsg) ) { // The value returned from this hookproc is ignored, // and it cannot be used to tell Windows the message has been handled. // To avoid further processing, convert the message to WM_NULL // before returning. lpMsg->message = WM_NULL; lpMsg->lParam = 0; lpMsg->wParam = 0; break; } } } } return CallNextHookEx ( mDialogHook, nCode, wParam, lParam); } /* ================ rvRollupPanel::AutoSize Automatically set the width of the control based on the dialogs it contains ================ */ void rvRollupPanel::AutoSize ( void ) { int i; int width = 0; for ( i = 0; i < mItems.Num(); i ++ ) { RECT r; int w; GetWindowRect ( mItems[i]->mDialog, &r ); w = (r.right-r.left)+RP_SCROLLBARWIDTH+(RP_GRPBOXINDENT*2); if ( w > width ) { width = w; } } RECT cr; GetWindowRect ( mWindow, &cr ); SetWindowPos ( mWindow, NULL, 0, 0, width, cr.bottom-cr.top, SWP_NOMOVE|SWP_NOZORDER ); }