mirror of
https://github.com/blendogames/quadrilateralcowboy.git
synced 2024-11-24 21:11:49 +00:00
1215 lines
25 KiB
C++
1215 lines
25 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 "../../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#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 );
|
|
}
|
|
|