dhewm3/neo/tools/common/RollupPanel.cpp
Daniel Gibson 9a95a2a1cf Building with editor support (on Win w/ VS2017) works \o/
Editor also seems to start, didn't test much further.

Only tested 32bit Windows, I fear the editor code isn't 64bit clean..

I hope I haven't broken anything elsewhere..
2019-01-13 22:52:28 +01:00

1214 lines
24 KiB
C++

/*
===========================================================================
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 <http://www.gnu.org/licenses/>.
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<HWND> 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) GetWindowLong ( dialog, DWL_DLGPROC );
item->mOldButtonProc = (WNDPROC) GetWindowLong ( button, GWL_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
SetWindowLong ( dialog, GWL_USERDATA, (LONG)item );
// Attach item to button through user data
SetWindowLong ( button, GWL_USERDATA, (LONG)item );
SetWindowLong ( button, GWL_ID, index );
// Subclass dialog
SetWindowLong ( dialog, DWL_DLGPROC, (LONG)DialogProc );
// SubClass button
SetWindowLong ( button, GWL_WNDPROC, (LONG)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*)GetWindowLong ( hWnd, GWL_USERDATA );
rvRollupPanel* _this = (rvRollupPanel*)GetWindowLong ( GetParent ( hWnd ), GWL_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*)GetWindowLong(hWnd, GWL_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*)GetWindowLong (hWnd, GWL_USERDATA);
switch ( uMsg )
{
case WM_CREATE:
{
LPCREATESTRUCT cs;
// Attach the class to the window first
cs = (LPCREATESTRUCT) lParam;
panel = (rvRollupPanel*) cs->lpCreateParams;
SetWindowLong ( hWnd, GWL_USERDATA, (LONG)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 );
}