mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
54d0ea80c3
better Unicode drawing function
4070 lines
95 KiB
C++
4070 lines
95 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "outliner.h"
|
|
#include "imagemap.h"
|
|
#include "prefapi.h"
|
|
#include "tip.h"
|
|
#include "fegui.h"
|
|
#ifdef _WIN32
|
|
#include "intelli.h"
|
|
#endif
|
|
|
|
#include "qahook.h" // rhp - added for QA Partner automated testing messages
|
|
|
|
#define COL_LEFT_MARGIN ((m_cxChar+1)/2)
|
|
#define OUTLINE_TEXT_OFFSET 8
|
|
|
|
#define ID_OUTLINER_HEARTBEAT 2
|
|
#define ID_OUTLINER_TIMER 3
|
|
#define ID_OUTLINER_TIMER_DELAY 500
|
|
|
|
#define OUTLINER_PERCENTFACTOR 10000
|
|
#ifndef _AFXDLL
|
|
#undef new
|
|
#endif
|
|
IMPLEMENT_DYNCREATE(COutlinerView, CView)
|
|
#ifndef _AFXDLL
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#ifndef _WIN32
|
|
HGDIOBJ GetCurrentObject(HDC hdc, UINT uObjectType)
|
|
{
|
|
HGDIOBJ res = NULL;
|
|
switch (uObjectType) {
|
|
case OBJ_BRUSH:
|
|
res = ::SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
::SelectObject(hdc, res);
|
|
break;
|
|
case OBJ_PEN:
|
|
res = ::SelectObject(hdc, GetStockObject(NULL_PEN));
|
|
::SelectObject(hdc, res);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COutliner
|
|
|
|
BOOL COutliner::m_bTipsEnabled = TRUE;
|
|
|
|
#define TIP_WAITING 1
|
|
#define TIP_SHOWING 2
|
|
#define TIP_SHOWN 3
|
|
#define TIP_HEARTBEAT 100
|
|
#define TIP_DELAY 250
|
|
|
|
#define DRAG_HEARTBEAT 250
|
|
|
|
BEGIN_MESSAGE_MAP(COutliner, CWnd)
|
|
ON_WM_SETCURSOR ( )
|
|
ON_WM_CREATE ( )
|
|
ON_WM_PAINT ( )
|
|
ON_WM_SIZE ( )
|
|
ON_WM_GETMINMAXINFO ( )
|
|
ON_WM_DESTROY ( )
|
|
ON_WM_LBUTTONDOWN ( )
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_RBUTTONDOWN ( )
|
|
ON_WM_RBUTTONUP()
|
|
ON_WM_VSCROLL ( )
|
|
ON_WM_SETFOCUS ( )
|
|
ON_WM_KILLFOCUS ( )
|
|
ON_WM_SYSKEYDOWN()
|
|
ON_WM_KEYDOWN ( )
|
|
ON_WM_KEYUP()
|
|
ON_WM_LBUTTONDBLCLK ( )
|
|
ON_WM_ERASEBKGND ( )
|
|
ON_WM_TIMER ( )
|
|
ON_WM_SYSCOLORCHANGE ( )
|
|
ON_WM_GETDLGCODE()
|
|
#if defined(XP_WIN32) && _MSC_VER >= 1100
|
|
ON_REGISTERED_MESSAGE(msg_MouseWheel, OnHackedMouseWheel)
|
|
ON_MESSAGE(WM_MOUSEWHEEL, OnMouseWheel)
|
|
#endif
|
|
|
|
// rhp - For QA partner message handling
|
|
ON_MESSAGE(WM_COPYDATA, OnProcessOLQAHook)
|
|
// rhp
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
class CNSOutlinerFactory : public CGenericFactory
|
|
{
|
|
public:
|
|
CNSOutlinerFactory();
|
|
~CNSOutlinerFactory();
|
|
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj);
|
|
};
|
|
|
|
CNSOutlinerFactory::CNSOutlinerFactory()
|
|
{
|
|
ApiApiPtr(api);
|
|
api->RegisterClassFactory(APICLASS_OUTLINER,this);
|
|
}
|
|
|
|
CNSOutlinerFactory::~CNSOutlinerFactory()
|
|
{
|
|
}
|
|
|
|
STDMETHODIMP CNSOutlinerFactory::CreateInstance(
|
|
LPUNKNOWN pUnkOuter,
|
|
REFIID refiid,
|
|
LPVOID * ppvObj)
|
|
{
|
|
COutliner * pOutliner = new COutliner;
|
|
*ppvObj = (LPVOID)((LPUNKNOWN)pOutliner);
|
|
return NOERROR;
|
|
}
|
|
|
|
DECLARE_FACTORY(CNSOutlinerFactory);
|
|
|
|
COutliner::COutliner ( BOOL bUseTriggerAndLineBitmaps )
|
|
{
|
|
#ifdef _WIN32
|
|
m_iWheelDelta = 0;
|
|
#endif
|
|
m_iDragSelection = -1;
|
|
m_iDragSelectionLineHalf = -1;
|
|
m_iDragSelectionLineThird = -1;
|
|
m_bDragSectionChanged = FALSE;
|
|
m_iLastSelected = -1;
|
|
m_iTotalLines = 0;
|
|
m_iTopLine = 0;
|
|
m_iSelection = -1;
|
|
m_iFocus = -1;
|
|
m_pColumn = NULL;
|
|
m_iNumColumns = 0;
|
|
m_iVisColumns = 0;
|
|
m_iTotalWidth = 0;
|
|
m_idImageCol = 0;
|
|
m_bHasPipes = TRUE;
|
|
m_bHasImageOnlyColumn = FALSE;
|
|
m_pDropTarget = NULL;
|
|
m_bDraggingData = FALSE;
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
m_bLButtonDown = FALSE;
|
|
|
|
m_pTip = new CTip();
|
|
m_pTip->Create();
|
|
|
|
m_iTipState = 0;
|
|
m_iTipTimer = 0;
|
|
m_iTipRow = m_iTipCol = -1;
|
|
|
|
m_hBoldFont = NULL;
|
|
m_hRegFont = NULL;
|
|
m_hItalFont = NULL;
|
|
|
|
m_pUnkImage = NULL;
|
|
m_pIImage = NULL;
|
|
|
|
if (bUseTriggerAndLineBitmaps)
|
|
{
|
|
ApiApiPtr(api);
|
|
m_pUnkImage = api->CreateClassInstance(
|
|
APICLASS_IMAGEMAP,NULL,(APISIGNATURE)GetOutlinerBitmap());
|
|
m_pUnkImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIImage);
|
|
ASSERT(m_pIImage);
|
|
if (!m_pIImage->GetResourceID())
|
|
m_pIImage->Initialize(GetOutlinerBitmap(),16,16);
|
|
}
|
|
}
|
|
|
|
COutliner::~COutliner ( )
|
|
{
|
|
if(m_pDropTarget) {
|
|
m_pDropTarget->Revoke();
|
|
delete m_pDropTarget;
|
|
m_pDropTarget = NULL;
|
|
}
|
|
|
|
if (m_pUnkImage) {
|
|
if (m_pIImage)
|
|
m_pUnkImage->Release();
|
|
}
|
|
|
|
if ( m_pColumn )
|
|
{
|
|
while ( m_iNumColumns )
|
|
{
|
|
if (m_pColumn[ m_iNumColumns - 1]->pHeader)
|
|
free((char*)m_pColumn[ m_iNumColumns - 1]->pHeader);
|
|
delete(m_pColumn[ m_iNumColumns - 1 ]);
|
|
m_iNumColumns--;
|
|
}
|
|
free(m_pColumn);
|
|
}
|
|
if (m_hBoldFont) {
|
|
theApp.ReleaseAppFont(m_hBoldFont);
|
|
}
|
|
if (m_hRegFont) {
|
|
theApp.ReleaseAppFont(m_hRegFont);
|
|
}
|
|
if (m_hItalFont) {
|
|
theApp.ReleaseAppFont(m_hItalFont);
|
|
}
|
|
|
|
delete m_pTip;
|
|
}
|
|
|
|
void COutliner::DestroyColumns()
|
|
{
|
|
if ( m_pColumn )
|
|
{
|
|
while ( m_iNumColumns )
|
|
{
|
|
if (m_pColumn[ m_iNumColumns - 1]->pHeader)
|
|
free((char*)m_pColumn[ m_iNumColumns - 1]->pHeader);
|
|
delete(m_pColumn[ m_iNumColumns - 1 ]);
|
|
m_iNumColumns--;
|
|
}
|
|
free(m_pColumn);
|
|
m_pColumn = NULL;
|
|
}
|
|
|
|
m_iNumColumns = 0;
|
|
}
|
|
|
|
STDMETHODIMP COutliner::QueryInterface(
|
|
REFIID refiid,
|
|
LPVOID * ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
if (IsEqualIID(refiid,IID_IOutliner))
|
|
*ppv = (LPIOUTLINER) this;
|
|
|
|
if (*ppv != NULL) {
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return CGenericObject::QueryInterface(refiid,ppv);
|
|
}
|
|
|
|
void COutliner::OnDestroy()
|
|
{
|
|
if (m_iTipTimer) {
|
|
KillTimer(m_iTipTimer);
|
|
m_iTipTimer = 0;
|
|
}
|
|
TipHide();
|
|
}
|
|
|
|
void COutliner::TipHide()
|
|
{
|
|
if (m_iTipTimer) {
|
|
KillTimer(m_iTipTimer);
|
|
m_iTipTimer = 0;
|
|
}
|
|
m_pTip->Hide();
|
|
m_iTipState = TIP_SHOWN;
|
|
}
|
|
|
|
void COutliner::EnableTips(BOOL s)
|
|
{
|
|
TipHide();
|
|
m_iTipState = 0;
|
|
m_bTipsEnabled = s;
|
|
}
|
|
|
|
BOOL COutliner::TestRowCol(POINT point, int &iRow, int &iCol)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
|
|
if (::PtInRect(&rcClient, point)) {
|
|
void *pLineData = NULL;
|
|
int iSel = point.y / m_itemHeight;
|
|
int iNewSel = m_iTopLine + iSel;
|
|
if ( ( pLineData = AcquireLineData ( iNewSel ) ) != NULL ) {
|
|
ReleaseLineData( pLineData );
|
|
int i, offset;
|
|
int y = iSel * m_itemHeight;
|
|
|
|
for ( i = 0, offset = 0; i < m_iVisColumns; i++ )
|
|
{
|
|
CRect rect ( offset, y,
|
|
offset + m_pColumn[ i ]->iCol, y + m_itemHeight );
|
|
|
|
if ( rect.PtInRect(point) )
|
|
{
|
|
iRow = iNewSel;
|
|
iCol = i;
|
|
m_rcHit = rect;
|
|
|
|
return TRUE;
|
|
}
|
|
offset += m_pColumn[ i ]->iCol;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
UINT COutliner::GetOutlinerBitmap(void)
|
|
{
|
|
return IDB_OUTLINER;
|
|
}
|
|
|
|
BOOL COutliner::OnEraseBkgnd( CDC * )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
int COutliner::GetIndentationWidth()
|
|
{
|
|
if (m_pIImage)
|
|
return m_pIImage->GetImageWidth();
|
|
return m_itemHeight;
|
|
}
|
|
|
|
int COutliner::GetColumnSize ( UINT idCol )
|
|
{
|
|
|
|
if ( m_pColumn )
|
|
for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )
|
|
if ( m_pColumn[ iColumn ]->iCommand == idCol )
|
|
return m_pColumn[ iColumn ]->iCol;
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::GetColumnPercent ( UINT idCol )
|
|
{
|
|
if ( m_pColumn )
|
|
for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )
|
|
if ( m_pColumn[ iColumn ]->iCommand == idCol )
|
|
return (int)(m_pColumn[ iColumn ]->fPercent * OUTLINER_PERCENTFACTOR);
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::GetColumnPos ( UINT idCol )
|
|
{
|
|
if ( m_pColumn )
|
|
for ( int iColumn = 0; iColumn < m_iNumColumns; iColumn++ )
|
|
if ( m_pColumn[ iColumn ]->iCommand == idCol )
|
|
return iColumn;
|
|
return -1;
|
|
}
|
|
|
|
UINT COutliner::GetColumnAtPos ( int iPos )
|
|
{
|
|
if ( m_pColumn )
|
|
if (iPos >= 0 && iPos < m_iNumColumns)
|
|
return m_pColumn[ iPos ]->iCommand;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::AddColumn (
|
|
LPCTSTR header, UINT command,
|
|
int iMinCol, int iMaxCol,
|
|
Column_t ColType,
|
|
int iPercent,
|
|
BOOL bButton,
|
|
CropType_t ct, AlignType_t at )
|
|
{
|
|
OutlinerColumn_t * pColumn = new OutlinerColumn_t;
|
|
pColumn->pHeader = _tcsdup(header);
|
|
pColumn->cType = ColType;
|
|
pColumn->bIsButton = bButton;
|
|
pColumn->iMinColSize = iMinCol;
|
|
pColumn->iMaxColSize = iMaxCol;
|
|
pColumn->fPercent = (FLOAT)((FLOAT)iPercent/(FLOAT)OUTLINER_PERCENTFACTOR);
|
|
pColumn->fDesiredPercent = pColumn->fPercent;
|
|
pColumn->iCol = iMinCol;
|
|
pColumn->bDepressed = 0;
|
|
pColumn->iCommand = command;
|
|
pColumn->cropping = ct;
|
|
pColumn->alignment = at;
|
|
if ( !m_pColumn )
|
|
m_pColumn = (OutlinerColumn_t **)malloc(sizeof(OutlinerColumn_t *));
|
|
else
|
|
m_pColumn = (OutlinerColumn_t **)realloc(m_pColumn,sizeof(OutlinerColumn_t*)*(m_iNumColumns+1));
|
|
m_pColumn[ m_iNumColumns ] = pColumn;
|
|
m_iVisColumns = ++m_iNumColumns;
|
|
|
|
return m_iNumColumns;
|
|
}
|
|
|
|
void COutliner::SetColumnPos ( UINT idCol, int iColumn ) {
|
|
int iOldColumn;
|
|
|
|
iOldColumn = GetColumnPos(idCol);
|
|
|
|
if ( (iOldColumn < 0) || (iColumn >= m_iNumColumns) || (iColumn < 0) )
|
|
return;
|
|
|
|
OutlinerColumn_t *temp;
|
|
temp = m_pColumn[ iColumn ];
|
|
m_pColumn[ iColumn ] = m_pColumn[ iOldColumn ];
|
|
m_pColumn[ iOldColumn ] = temp;
|
|
|
|
Invalidate ( );
|
|
}
|
|
|
|
void COutliner::SetColumnName ( UINT idCol, LPCTSTR pName )
|
|
{
|
|
int iColumn;
|
|
if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
|
|
return;
|
|
|
|
if (m_pColumn[ iColumn ]->pHeader)
|
|
free((char*)m_pColumn[ iColumn ]->pHeader);
|
|
m_pColumn[ iColumn ]->pHeader = _tcsdup(pName);
|
|
}
|
|
|
|
void COutliner::SetColumnSize ( UINT idCol, int iSize )
|
|
{
|
|
int iColumn;
|
|
if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
|
|
return;
|
|
|
|
m_pColumn[ iColumn ]->iCol = iSize;
|
|
}
|
|
|
|
void COutliner::SetColumnPercent ( UINT idCol, int iPercent )
|
|
{
|
|
int iColumn;
|
|
if ( ( iColumn = GetColumnPos( idCol ) ) < 0 )
|
|
return;
|
|
|
|
m_pColumn[ iColumn ]->fPercent = m_pColumn[iColumn]->fDesiredPercent = (FLOAT)((FLOAT)iPercent/(FLOAT)OUTLINER_PERCENTFACTOR);
|
|
}
|
|
|
|
void COutliner::LoadXPPrefs( const char *prefname )
|
|
{
|
|
int i, j;
|
|
|
|
char buf[256];
|
|
char *formatString = buf;
|
|
int iLen = 256;
|
|
memset(formatString, 0, 256);
|
|
PREF_GetCharPref(prefname, formatString, &iLen);
|
|
char *end = formatString + iLen;
|
|
|
|
if ( formatString[0] == 'v' && formatString[1] == '1') {
|
|
formatString += 2;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
i = 0;
|
|
j = 0;
|
|
|
|
int nVis;
|
|
if (sscanf(formatString, " %d %n", &nVis, &j) == 1) {
|
|
formatString += j;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
while (formatString < end && formatString[0]) {
|
|
int id, nWidth;
|
|
|
|
if (sscanf(formatString, " %d : %d %n", &id, &nWidth, &j) == 2) {
|
|
|
|
// We should really check these values in case
|
|
// someone mucks with their registry.
|
|
|
|
SetColumnPos( id, i );
|
|
SetColumnPercent( id, nWidth );
|
|
|
|
formatString += j;
|
|
i++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetVisibleColumns( nVis );
|
|
|
|
// Make it so
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
OnSize(0, rcClient.right, rcClient.bottom);
|
|
|
|
GetParent()->Invalidate();
|
|
}
|
|
|
|
BOOL COutliner::GetIsColumnVisible( int columnID )
|
|
{
|
|
for (int i = 0; i < m_iVisColumns; i++) {
|
|
if ((UINT) columnID == GetColumnAtPos(i))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void COutliner::SaveXPPrefs( const char *prefname )
|
|
{
|
|
CString cs, cs2;
|
|
|
|
cs = "v1";
|
|
cs2.Format(" %d", GetVisibleColumns());
|
|
cs += cs2;
|
|
for (int i = 0; i < m_iNumColumns; i++) {
|
|
cs2.Format(_T(" %d:%d"),
|
|
GetColumnAtPos(i),
|
|
GetColumnPercent(GetColumnAtPos(i)));
|
|
cs += cs2;
|
|
}
|
|
|
|
PREF_SetCharPref( prefname, cs );
|
|
}
|
|
|
|
void COutliner::OnSize( UINT nType, int cx, int cy )
|
|
{
|
|
SqueezeColumns( -1, 0, FALSE );
|
|
m_iPaintLines = ( cy / m_itemHeight ) + 1;
|
|
EnableScrollBars ( );
|
|
}
|
|
|
|
void COutliner::OnGetMinMaxInfo ( MINMAXINFO FAR* lpMMI )
|
|
{
|
|
CWnd::OnGetMinMaxInfo( lpMMI );
|
|
int max = 0, min = 0;
|
|
int i;
|
|
|
|
for ( i = 0; i < m_iVisColumns; i++ ) {
|
|
if (max >= 0) {
|
|
if (m_pColumn[ i ]->iMaxColSize > 0) {
|
|
max += m_pColumn[ i ]->iMaxColSize;
|
|
} else {
|
|
max = -1;
|
|
}
|
|
}
|
|
if (min >= 0) {
|
|
if (m_pColumn[ i ]->iMinColSize > 0) {
|
|
min += m_pColumn[ i ]->iMinColSize;
|
|
}
|
|
}
|
|
}
|
|
if (max >= 0) {
|
|
lpMMI->ptMaxSize.x;
|
|
lpMMI->ptMaxTrackSize.x;
|
|
}
|
|
if (min >= 0) {
|
|
lpMMI->ptMinTrackSize.x;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Sizes variable width columns to fit the current width of the outliner.
|
|
//
|
|
// iColFrom: -1 implies all columns will size to fit.
|
|
// 0+ implies the column is sizing and all following columns will size to fit.
|
|
//
|
|
// iDelta: Specifies the delta for the size. If 0, all columns adjust to size.
|
|
//
|
|
// bRepaint: Repaint all the affected columns after the size.
|
|
//
|
|
BOOL COutliner::SqueezeColumns( int iColFrom /*=-1*/, int iDelta /*=0*/, BOOL bRepaint /*=TRUE*/ )
|
|
{
|
|
ASSERT( iColFrom >= -1 );
|
|
|
|
if( m_iVisColumns == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT( iColFrom < m_iVisColumns );
|
|
|
|
if( (iColFrom != -1) && (iDelta == 0) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CFont *pOldFont = NULL;
|
|
CDC *pDC = GetDC();
|
|
if( GetFont() )
|
|
{
|
|
pOldFont = pDC->SelectObject( GetFont() );
|
|
}
|
|
CSize csMinWidth = pDC->GetTextExtent( "W", _tcslen( "W" ) );
|
|
if( pOldFont )
|
|
{
|
|
pDC->SelectObject( pOldFont );
|
|
}
|
|
ReleaseDC( pDC );
|
|
|
|
//
|
|
// Calculate variable column width and percent
|
|
//
|
|
LONG iVariableWidth = m_iTotalWidth;
|
|
LONG iActualVariableWidth = 0;
|
|
FLOAT fDesiredVariablePercent = (FLOAT)0;
|
|
int iOldRightWidth = 0;
|
|
LONG iActualTotalWidth = 0;
|
|
BOOL bResetPercents = FALSE;
|
|
int i;
|
|
int iMinLeftWidth = 0;
|
|
for( i = 0; i < m_iVisColumns; i++ )
|
|
{
|
|
if( m_pColumn[i]->cType == ColumnVariable )
|
|
{
|
|
if( i <= iColFrom )
|
|
{
|
|
iOldRightWidth += m_pColumn[i]->iCol;
|
|
}
|
|
else
|
|
{
|
|
if( bResetPercents || (m_pColumn[i]->fPercent == m_pColumn[i]->fDesiredPercent) )
|
|
{
|
|
bResetPercents = TRUE;
|
|
|
|
m_pColumn[i]->fDesiredPercent = m_pColumn[i]->fPercent;
|
|
}
|
|
iMinLeftWidth += csMinWidth.cx; //max( m_pColumn[i]->iMinColSize, csMinWidth.cx );
|
|
}
|
|
|
|
fDesiredVariablePercent += m_pColumn[i]->fDesiredPercent;
|
|
|
|
// Only used when iDelta is not specified and is calculated e.g., during window size
|
|
iActualVariableWidth += m_pColumn[i]->iCol;
|
|
}
|
|
else
|
|
{
|
|
if( i > iColFrom )
|
|
{
|
|
iMinLeftWidth += m_pColumn[i]->iCol;
|
|
}
|
|
|
|
iVariableWidth -= m_pColumn[i]->iCol;
|
|
}
|
|
|
|
iActualTotalWidth += m_pColumn[i]->iCol;
|
|
}
|
|
|
|
if( (iColFrom == -1) && (iDelta == 0) )
|
|
{
|
|
//
|
|
// We must calculate the delta when iColFrom is -1. Most likely the outliner's window
|
|
// has changed size.
|
|
//
|
|
iDelta = CASTINT(iActualTotalWidth - m_iTotalWidth);
|
|
}
|
|
|
|
if( iVariableWidth < 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LONG iSurplus = iVariableWidth;
|
|
|
|
if( fDesiredVariablePercent == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Calculate the smallest allowable variable column width and percent
|
|
//
|
|
FLOAT fMinPercent = (FLOAT)csMinWidth.cx/(FLOAT)iVariableWidth;
|
|
|
|
if( (iColFrom != -1) && (iDelta < 0) && (m_pColumn[iColFrom]->fPercent <= fMinPercent) )
|
|
{
|
|
// Can't size it any smaller
|
|
return FALSE;
|
|
}
|
|
|
|
int iNewLeftWidth = 0;
|
|
|
|
//
|
|
// Enforce the delta limit for left sizing
|
|
//
|
|
if( (iColFrom != -1) && ((m_pColumn[iColFrom]->iCol + iDelta) <= csMinWidth.cx) )
|
|
{
|
|
iDelta = m_pColumn[iColFrom]->iCol - csMinWidth.cx;
|
|
}
|
|
|
|
//
|
|
// Enforce the delta limit for right sizing
|
|
//
|
|
int iNumLeftCols = (m_iVisColumns - iColFrom) - 1;
|
|
int iNewRightWidth = iOldRightWidth + iDelta;
|
|
iMinLeftWidth = iNumLeftCols * csMinWidth.cx;
|
|
|
|
iNewLeftWidth = CASTINT(((iColFrom == -1) ? iActualVariableWidth : iVariableWidth) - iNewRightWidth);
|
|
|
|
BOOL bSign = (iDelta > 0);
|
|
|
|
if( iNewLeftWidth < iMinLeftWidth )
|
|
{
|
|
iDelta -= (iMinLeftWidth - iNewLeftWidth);
|
|
iNewLeftWidth = CASTINT(iVariableWidth - (iOldRightWidth + iDelta));
|
|
iNewRightWidth = CASTINT(iVariableWidth - iNewLeftWidth);
|
|
ASSERT( iNewRightWidth == (iOldRightWidth + iDelta) );
|
|
}
|
|
|
|
if( iNewLeftWidth < iMinLeftWidth )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if( iDelta == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if( bSign != (iDelta > 0) )
|
|
{
|
|
// The sign should not have changed, but just to be safe...
|
|
return FALSE;
|
|
}
|
|
|
|
FLOAT fNewLeftPercent = (FLOAT)iNewLeftWidth/(FLOAT)iVariableWidth;
|
|
|
|
for( i = 0; i < m_iVisColumns; i++ )
|
|
{
|
|
if( m_pColumn[i]->cType != ColumnVariable )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( i < iColFrom )
|
|
{
|
|
// Column's to the right of the sizing column don't change, so just decrement the var percent
|
|
|
|
fDesiredVariablePercent -= m_pColumn[i]->fDesiredPercent;
|
|
}
|
|
else if( i == iColFrom )
|
|
{
|
|
// Decrement the percent BEFORE we calc the new percent
|
|
|
|
fDesiredVariablePercent -= m_pColumn[i]->fDesiredPercent;
|
|
|
|
// Add the delta and calc the new percent
|
|
|
|
m_pColumn[i]->iCol += iDelta;
|
|
m_pColumn[i]->fPercent = (FLOAT)m_pColumn[i]->iCol/(FLOAT)iVariableWidth;
|
|
m_pColumn[i]->fDesiredPercent = m_pColumn[i]->fPercent;
|
|
}
|
|
else
|
|
{
|
|
FLOAT fPrevPercent = m_pColumn[i]->fPercent;
|
|
FLOAT fPrevDesiredPercent = m_pColumn[i]->fDesiredPercent;
|
|
|
|
m_pColumn[i]->fPercent = fNewLeftPercent * m_pColumn[i]->fDesiredPercent/fDesiredVariablePercent;
|
|
m_pColumn[i]->fPercent = max( m_pColumn[i]->fPercent, fMinPercent );
|
|
|
|
m_pColumn[i]->iCol = (int)((FLOAT)iNewLeftWidth * m_pColumn[i]->fPercent/fNewLeftPercent);
|
|
m_pColumn[i]->iCol = max( m_pColumn[i]->iCol, csMinWidth.cx );
|
|
}
|
|
|
|
iSurplus -= m_pColumn[i]->iCol;
|
|
}
|
|
|
|
//
|
|
// Consume the surplus space somewhat evenly
|
|
//
|
|
while( iSurplus )
|
|
{
|
|
for( i = iColFrom+1; i < m_iVisColumns; i++ )
|
|
{
|
|
if( m_pColumn[i]->cType != ColumnVariable )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( iSurplus > 0 )
|
|
{
|
|
m_pColumn[i]->iCol += 1;
|
|
iSurplus--;
|
|
}
|
|
else if( m_pColumn[i]->iCol > csMinWidth.cx )
|
|
{
|
|
m_pColumn[i]->iCol -= 1;
|
|
iSurplus++;
|
|
}
|
|
|
|
if( !iSurplus )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bRepaint )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
for( i = iColFrom; i < m_iVisColumns; i++)
|
|
{
|
|
InvalidateColumn( i );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// iDesiredSize is what the outliner wants to be. In this default case
|
|
// we use this height.
|
|
void COutliner::InitializeItemHeight(int iDesiredSize)
|
|
{
|
|
m_itemHeight = iDesiredSize;
|
|
|
|
}
|
|
|
|
void COutliner::PropertyMenu( int iLine, UINT flags )
|
|
{
|
|
}
|
|
|
|
BOOL COutliner::ColumnCommand( int iCol, int iLine )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void COutliner::InitializeClipFormats()
|
|
{
|
|
}
|
|
|
|
void COutliner::OnRButtonDown ( UINT nFlags, CPoint point )
|
|
{
|
|
TipHide();
|
|
CWnd::OnRButtonDown ( nFlags, point );
|
|
m_ptHit = point;
|
|
int iSel = m_iTopLine + (point.y / m_itemHeight);
|
|
if (iSel >= m_iTotalLines) // Nothing to select
|
|
return;
|
|
SelectItem( iSel, OUTLINER_RBUTTONDOWN );
|
|
}
|
|
|
|
void COutliner::OnRButtonUp( UINT nFlags, CPoint point )
|
|
{
|
|
m_ptHit = point;
|
|
int iSel = m_iTopLine + (point.y / m_itemHeight);
|
|
|
|
PropertyMenu( iSel, nFlags );
|
|
}
|
|
|
|
void COutliner::HandleMouseMove( POINT point )
|
|
{
|
|
if (m_bTipsEnabled) {
|
|
int iRow, iCol;
|
|
CPoint ptCorner;
|
|
|
|
// make sure the outline itself is active
|
|
#ifdef _WIN32
|
|
CWnd* pParent = GetParentOwner();
|
|
#else
|
|
CWnd* pParent = GetParent();
|
|
if (pParent)
|
|
{
|
|
LONG lStyle = GetWindowLong(pParent->GetSafeHwnd(), GWL_STYLE);
|
|
while ((lStyle & WS_CHILD) && (pParent = pParent->GetParent()))
|
|
{
|
|
lStyle = GetWindowLong(pParent->GetSafeHwnd(), GWL_STYLE);
|
|
}
|
|
}
|
|
#endif
|
|
if ((pParent != GetActiveWindow()) || !pParent->IsWindowEnabled()) {
|
|
TipHide();
|
|
return;
|
|
}
|
|
|
|
// check for this application tracking (capture set)
|
|
CWnd* pCapture = GetCapture();
|
|
if (pCapture) {
|
|
TipHide();
|
|
return;
|
|
}
|
|
|
|
if (TestRowCol(point, iRow, iCol)) {
|
|
if (( iCol != m_iTipCol) || (iRow != m_iTipRow)) {
|
|
ASSERT(iCol < m_iNumColumns);
|
|
ASSERT(iRow < m_iTotalLines);
|
|
m_iTipRow = iRow;
|
|
m_iTipCol = iCol;
|
|
|
|
switch (m_iTipState) {
|
|
case 0: case TIP_WAITING:
|
|
m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, TIP_DELAY, NULL);
|
|
break;
|
|
case TIP_SHOWING:
|
|
m_pTip->Hide();
|
|
m_iTipState = TIP_WAITING;
|
|
m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, TIP_HEARTBEAT, NULL);
|
|
break;
|
|
case TIP_SHOWN:
|
|
break;
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
TipHide();
|
|
m_iTipCol = -1;
|
|
m_iTipRow = -1;
|
|
m_iTipState = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void COutliner::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (GetCapture() == this) {
|
|
// See if the mouse has moved far enough to start
|
|
// a drag operation
|
|
if ((abs(point.x - m_ptHit.x) > 3)
|
|
|| (abs(point.y - m_ptHit.y) > 3)) {
|
|
// release the mouse capture
|
|
ReleaseCapture();
|
|
InitiateDragDrop();
|
|
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
|
|
}
|
|
}
|
|
if (m_iTipState != TIP_SHOWING)
|
|
m_iTipState = TIP_WAITING;
|
|
HandleMouseMove( point );
|
|
}
|
|
|
|
void COutliner::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if (GetCapture() == this) {
|
|
ReleaseCapture();
|
|
SelectItem( m_iSelection, OUTLINER_LBUTTONUP, nFlags );
|
|
}
|
|
}
|
|
|
|
void COutliner::OnLButtonDown ( UINT nFlags, CPoint point )
|
|
{
|
|
Default();
|
|
TipHide();
|
|
|
|
SetFocus();
|
|
|
|
m_ptHit = point;
|
|
|
|
int iRow, iCol;
|
|
|
|
if ( TestRowCol( point, iRow, iCol ) ){
|
|
m_iRowHit = iRow;
|
|
m_iColHit = iCol;
|
|
|
|
if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) {
|
|
void * pLineData;
|
|
if ( ( pLineData = AcquireLineData ( iRow ) ) ) {
|
|
int iDepth;
|
|
GetTreeInfo ( iRow, NULL, &iDepth, NULL );
|
|
ReleaseLineData ( pLineData );
|
|
|
|
int iImageWidth = GetIndentationWidth();
|
|
RECT rcToggle = m_rcHit;
|
|
rcToggle.left += iDepth * iImageWidth;
|
|
rcToggle.right = rcToggle.left + iImageWidth;
|
|
|
|
if ( ::PtInRect( &rcToggle, point ) ) {
|
|
DoToggleExpansion ( iRow );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if ( ColumnCommand( m_pColumn[ iCol ]->iCommand, iRow) )
|
|
return;
|
|
|
|
//Set m_bLButtonDown = true when really select an item,
|
|
//use in CFolderOutliner and CMessageOutliner for checking
|
|
//double click before really load a folder or message.
|
|
//Other outliner should not care for it.
|
|
m_bLButtonDown = TRUE;
|
|
SetCapture();
|
|
SelectItem( iRow, OUTLINER_LBUTTONDOWN, nFlags );
|
|
}
|
|
}
|
|
|
|
void COutliner::OnLButtonDblClk ( UINT nFlags, CPoint point )
|
|
{
|
|
Default();
|
|
TipHide();
|
|
|
|
int iRow, iCol;
|
|
|
|
if (TestRowCol( point, iRow, iCol )) {
|
|
if ( m_pColumn[ iCol ]->iCommand == m_idImageCol ) {
|
|
void * pLineData;
|
|
if ( ( pLineData = AcquireLineData ( iRow ) ) ) {
|
|
int iDepth;
|
|
GetTreeInfo ( iRow, NULL, &iDepth, NULL );
|
|
ReleaseLineData ( pLineData );
|
|
|
|
int iImageWidth = GetIndentationWidth();
|
|
RECT rcToggle = m_rcHit;
|
|
rcToggle.left += iDepth * iImageWidth;
|
|
rcToggle.right = rcToggle.left + iImageWidth;
|
|
|
|
if ( ::PtInRect( &rcToggle, point ) ) {
|
|
DoToggleExpansion ( iRow );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if ( ColumnCommand( m_pColumn[ iCol ]->iCommand, iRow ) )
|
|
return;
|
|
|
|
SetCapture();
|
|
SelectItem( iRow, OUTLINER_LBUTTONDBLCLK, nFlags );
|
|
}
|
|
}
|
|
|
|
int COutliner::GetTotalLines()
|
|
{
|
|
return m_iTotalLines;
|
|
}
|
|
|
|
int COutliner::GetDropLine()
|
|
{
|
|
return m_iDragSelection;
|
|
}
|
|
|
|
int COutliner::GetDragHeartbeat()
|
|
{
|
|
// Override to set a different drag time on scroll.
|
|
return DRAG_HEARTBEAT;
|
|
}
|
|
|
|
HFONT COutliner::GetLineFont(void *pData)
|
|
{
|
|
return m_hRegFont;
|
|
}
|
|
|
|
void COutliner::SetFocusLine( int iLine )
|
|
{
|
|
if (iLine == -1)
|
|
return;
|
|
InvalidateLine(m_iFocus);
|
|
m_iFocus = iLine;
|
|
InvalidateLine(m_iFocus);
|
|
}
|
|
|
|
int COutliner::GetFocusLine()
|
|
{
|
|
return m_iFocus;
|
|
}
|
|
|
|
int COutliner::GetDepth( int iLine )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::GetNumChildren( int iLine )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::GetParentIndex( int iLine )
|
|
{
|
|
int depth = GetDepth( iLine );
|
|
if ( iLine > 0 ) {
|
|
int i = iLine - 1;
|
|
while ( i > 0 && GetDepth( i ) >= depth ) {
|
|
i--;
|
|
}
|
|
return i;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
BOOL COutliner::IsCollapsed( int iLine )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void *COutliner::AcquireLineData( int iLine )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void COutliner::ReleaseLineData( void *pData )
|
|
{
|
|
|
|
}
|
|
|
|
LPCTSTR COutliner::GetColumnText( UINT iCol, void *pData )
|
|
{
|
|
return _T("");
|
|
}
|
|
|
|
LPCTSTR COutliner::GetColumnTip( UINT iCol, void *pData )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
BOOL COutliner::RenderData ( UINT idCol, CRect &rect, CDC &dc, LPCTSTR lpsz )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
int COutliner::Expand(int iLine)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::Collapse(int iLine)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::ToggleExpansion(int iLine)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::ExpandAll(int iLine)
|
|
{
|
|
return DoExpandAll(iLine);
|
|
}
|
|
|
|
int COutliner::CollapseAll(int iLine)
|
|
{
|
|
return DoCollapseAll(iLine);
|
|
}
|
|
|
|
void COutliner::GetTreeInfo( int iLine, unsigned long *pFlags, int *iDepth,
|
|
OutlinerAncestorInfo **pAncestor )
|
|
{
|
|
|
|
}
|
|
|
|
int COutliner::TranslateIcon( void *pData )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int COutliner::TranslateIconFolder( void *pData )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void COutliner::SelectItem( int iSel, int mode, UINT flags )
|
|
{
|
|
void *pData;
|
|
if ( pData = AcquireLineData( iSel ) ) {
|
|
ReleaseLineData( pData );
|
|
switch ( mode ) {
|
|
case OUTLINER_LBUTTONDOWN:
|
|
InvalidateLine( m_iSelection );
|
|
m_iSelection = iSel;
|
|
InvalidateLine( m_iSelection );
|
|
break;
|
|
|
|
case OUTLINER_LBUTTONUP:
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection;
|
|
InvalidateLine( m_iFocus );
|
|
OnSelChanged();
|
|
m_iLastSelected = m_iSelection;
|
|
break;
|
|
|
|
case 0:
|
|
ASSERT(0);
|
|
|
|
case OUTLINER_RBUTTONDOWN:
|
|
case OUTLINER_KEYDOWN:
|
|
case OUTLINER_SET:
|
|
InvalidateLine( m_iFocus );
|
|
InvalidateLine( m_iSelection );
|
|
m_iFocus = m_iSelection = iSel;
|
|
OnSelChanged();
|
|
m_iLastSelected = m_iSelection;
|
|
break;
|
|
|
|
case OUTLINER_LBUTTONDBLCLK:
|
|
case OUTLINER_RETURN:
|
|
OnSelDblClk();
|
|
break;
|
|
|
|
default:
|
|
ASSERT("What kind of garbage are you passing me?" == NULL);
|
|
}
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
void COutliner::InvalidateLine ( int iLineNo )
|
|
{
|
|
if (iLineNo == -1)
|
|
return;
|
|
CRect rect, out;
|
|
GetClientRect ( &rect );
|
|
RectFromLine ( iLineNo - m_iTopLine, rect, out );
|
|
InvalidateRect ( &out );
|
|
}
|
|
|
|
void COutliner::InvalidateLines( int iStart, int iCount )
|
|
{
|
|
RECT rect, out;
|
|
|
|
// Sanity check away
|
|
int iInvStart = iStart - m_iTopLine;
|
|
if (iInvStart < 0) {
|
|
// Off top
|
|
iCount += iInvStart;
|
|
iInvStart = 0;
|
|
}
|
|
|
|
if (iInvStart > m_iPaintLines)
|
|
// Nothing visible changed
|
|
return;
|
|
|
|
int iInvCount = (iInvStart + iCount) > m_iPaintLines ?
|
|
m_iPaintLines - iInvStart : iCount;
|
|
|
|
if (iInvCount < 0)
|
|
// Nothing visible changed
|
|
return;
|
|
|
|
// The case iInvCount < 0 is handled by for loop
|
|
|
|
GetClientRect ( &rect );
|
|
::SetRect ( &out,
|
|
rect.left, m_itemHeight * iInvStart,
|
|
rect.right, m_itemHeight * (iInvStart + iInvCount) );
|
|
|
|
InvalidateRect ( &out );
|
|
}
|
|
|
|
BOOL COutliner::HighlightIfDragging(void)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void COutliner::GetColumnRect( int iCol, RECT &rc )
|
|
{
|
|
GetClientRect(&rc);
|
|
rc.left = 0;
|
|
rc.right = 0;
|
|
if ( iCol >= 0 && iCol < m_iVisColumns ) {
|
|
for (int i = 0; i <= iCol; i++) {
|
|
rc.left = rc.right;
|
|
rc.right += m_pColumn[ i ]->iCol;
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutliner::InvalidateColumn( int iCol )
|
|
{
|
|
RECT rc;
|
|
GetColumnRect( iCol, rc );
|
|
InvalidateRect( &rc );
|
|
}
|
|
|
|
void COutliner::OnTimer( UINT timer)
|
|
{
|
|
if (timer == ID_OUTLINER_TIMER) {
|
|
int flags = 0;
|
|
if (GetKeyState(VK_SHIFT)&0x8000)
|
|
flags |= MK_SHIFT;
|
|
if (GetKeyState(VK_CONTROL)&0x8000)
|
|
flags |= MK_CONTROL;
|
|
SelectItem( m_iSelection,OUTLINER_TIMER, flags);
|
|
KillTimer(ID_OUTLINER_TIMER);
|
|
return;
|
|
}
|
|
if (timer == ID_OUTLINER_HEARTBEAT) {
|
|
POINT point;
|
|
GetCursorPos(&point);
|
|
ScreenToClient(&point);
|
|
|
|
if (m_iTipState == TIP_WAITING) {
|
|
CPoint ptCorner;
|
|
int iRow, iCol;
|
|
|
|
if (TestRowCol(point, iRow, iCol)) {
|
|
void * pLineData;
|
|
if ( pLineData = AcquireLineData ( m_iTipRow ) ) {
|
|
if ( ( iRow == m_iTipRow ) && ( iCol == m_iTipCol ) ) {
|
|
int x = 0;
|
|
if ( m_pColumn[ m_iTipCol ]->iCommand == m_idImageCol ) {
|
|
int iDepth = 0;
|
|
int iImageWidth = GetIndentationWidth();
|
|
if ( m_bHasPipes ) {
|
|
GetTreeInfo ( m_iTipRow, NULL, &iDepth, NULL );
|
|
x += (iDepth + 1) * iImageWidth;
|
|
}
|
|
x += iImageWidth + OUTLINE_TEXT_OFFSET;
|
|
}
|
|
if ( m_pTip ) {
|
|
HFONT hTipFont = GetLineFont(pLineData);
|
|
LPCSTR lpszTipText = GetColumnTip(m_pColumn[ m_iTipCol ]->iCommand, pLineData);
|
|
DWORD dwStyle = IsSelected( iRow ) ? NSTTS_SELECTED : 0;
|
|
if (!lpszTipText) {
|
|
lpszTipText = GetColumnText(m_pColumn[ m_iTipCol ]->iCommand, pLineData);
|
|
} else {
|
|
dwStyle |= NSTTS_ALWAYSSHOW;
|
|
}
|
|
dwStyle |= m_pColumn[ m_iTipCol ]->alignment == AlignRight ? NSTTS_RIGHT : 0;
|
|
|
|
int left = m_rcHit.left + x;
|
|
int top = m_rcHit.top;
|
|
int horExtent = m_pColumn[m_iTipCol]->iCol - x;
|
|
int vertExtent = m_itemHeight;
|
|
|
|
AdjustTipSize(left, top, horExtent, vertExtent);
|
|
|
|
m_pTip->Show( this->GetSafeHwnd(),
|
|
left, top, horExtent, vertExtent,
|
|
lpszTipText,dwStyle, hTipFont);
|
|
m_iTipState = TIP_SHOWING;
|
|
if ( !(m_iTipTimer = SetTimer( ID_OUTLINER_HEARTBEAT, 100, NULL )) )
|
|
// Can't get timer, so give up
|
|
TipHide();
|
|
}
|
|
} else {
|
|
m_iTipTimer = SetTimer(ID_OUTLINER_HEARTBEAT, 100, NULL);
|
|
}
|
|
|
|
ReleaseLineData(pLineData);
|
|
return;
|
|
}
|
|
}
|
|
// For whatever reason we shouldn't show
|
|
TipHide();
|
|
} else { // Since we're not waiting we must be showing
|
|
HandleMouseMove(point);
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutliner::PositionNext ( void )
|
|
{
|
|
if ( m_iFocus < m_iTotalLines - 1 ) {
|
|
m_iFocus++;
|
|
}
|
|
}
|
|
|
|
void COutliner::PositionPrevious ( void )
|
|
{
|
|
if ( m_iFocus > 0 ) {
|
|
m_iFocus--;
|
|
}
|
|
}
|
|
|
|
void COutliner::PositionHome ( void )
|
|
{
|
|
m_iFocus = 0;
|
|
m_iTopLine = 0;
|
|
}
|
|
|
|
void COutliner::PositionEnd ( void )
|
|
{
|
|
m_iFocus = m_iTotalLines - 1;
|
|
if (m_iFocus > ( m_iTopLine + m_iPaintLines - 2 ) ) {
|
|
m_iTopLine = m_iFocus - (m_iPaintLines - 2);
|
|
}
|
|
}
|
|
|
|
void COutliner::PositionPageDown()
|
|
{
|
|
if ( ( m_iFocus + m_iPaintLines ) > m_iTotalLines ) {
|
|
m_iFocus = m_iTotalLines - 1;
|
|
} else {
|
|
m_iFocus += m_iPaintLines - 2;
|
|
}
|
|
}
|
|
|
|
void COutliner::PositionPageUp()
|
|
{
|
|
if ( ( m_iFocus - m_iPaintLines - 2) < 0 ){
|
|
m_iFocus = 0;
|
|
} else {
|
|
m_iFocus -= m_iPaintLines - 2;
|
|
}
|
|
}
|
|
|
|
void COutliner::OnSysKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
TipHide();
|
|
switch (nChar) {
|
|
case VK_RETURN:
|
|
if (m_iFocus >= 0)
|
|
SelectItem(m_iFocus,OUTLINER_PROPERTIES);
|
|
break;
|
|
}
|
|
CWnd::OnSysKeyDown(nChar,nRepCnt,nFlags);
|
|
}
|
|
|
|
void COutliner::OnKeyUp ( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
Default();
|
|
if (m_iSelection != m_iLastSelected)
|
|
SetTimer(ID_OUTLINER_TIMER,ID_OUTLINER_TIMER_DELAY,NULL);
|
|
}
|
|
|
|
void COutliner::OnKeyDown ( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
int iOldSel = m_iSelection;
|
|
int iOldTopLine = m_iTopLine;
|
|
|
|
TipHide();
|
|
|
|
if ( (GetKeyState(VK_CONTROL)&0x8000) && (nChar != VK_DELETE) ) {
|
|
int nSBCode = -1;
|
|
switch (nChar) {
|
|
case VK_DOWN:
|
|
nSBCode = SB_LINEDOWN;
|
|
break;
|
|
|
|
case VK_UP:
|
|
nSBCode = SB_LINEUP;
|
|
break;
|
|
|
|
case VK_NEXT:
|
|
nSBCode = SB_PAGEDOWN;
|
|
break;
|
|
|
|
case VK_PRIOR:
|
|
nSBCode = SB_PAGEUP;
|
|
break;
|
|
|
|
case VK_HOME:
|
|
nSBCode = SB_TOP;
|
|
break;
|
|
|
|
case VK_END:
|
|
nSBCode = SB_BOTTOM;
|
|
break;
|
|
|
|
default:
|
|
Default();
|
|
}
|
|
if ( nSBCode != -1 ) {
|
|
OnVScroll( nSBCode, 0, GetScrollBarCtrl( SB_VERT ));
|
|
}
|
|
return;
|
|
} else {
|
|
switch (nChar) {
|
|
case VK_DELETE:
|
|
DeleteItem ( m_iSelection );
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
PositionNext();
|
|
break;
|
|
|
|
case VK_UP:
|
|
PositionPrevious();
|
|
break;
|
|
|
|
case VK_LEFT:
|
|
if ( GetNumChildren( m_iSelection ) > 0 && !IsCollapsed( m_iSelection ) ) {
|
|
DoCollapse( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by DoCollapse
|
|
} else {
|
|
int idx = GetParentIndex( m_iSelection );
|
|
SelectItem( idx );
|
|
ScrollIntoView( idx );
|
|
}
|
|
break;
|
|
|
|
case VK_RIGHT:
|
|
if ( GetNumChildren( m_iSelection ) > 0 ) {
|
|
if ( IsCollapsed( m_iSelection ) ) {
|
|
DoExpand( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by DoExpand
|
|
} else {
|
|
PositionNext();
|
|
}
|
|
}
|
|
break;
|
|
case VK_NEXT:
|
|
PositionPageDown();
|
|
break;
|
|
|
|
case VK_PRIOR:
|
|
PositionPageUp();
|
|
break;
|
|
|
|
case VK_MENU:
|
|
if (GetAsyncKeyState(VK_RETURN)&0x80)
|
|
SelectItem( m_iSelection,OUTLINER_PROPERTIES);
|
|
break;
|
|
case VK_RETURN:
|
|
SelectItem ( m_iFocus, OUTLINER_RETURN );
|
|
break;
|
|
|
|
case VK_HOME:
|
|
PositionHome ( );
|
|
break;
|
|
|
|
case VK_END:
|
|
PositionEnd ( );
|
|
break;
|
|
|
|
case VK_SUBTRACT:
|
|
if( m_iSelection >= 0 ) {
|
|
DoCollapse( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by DoCollapse
|
|
}
|
|
break;
|
|
|
|
case VK_ADD:
|
|
if( m_iSelection >= 0 ) {
|
|
DoExpand( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by DoExpand
|
|
}
|
|
break;
|
|
|
|
case VK_SPACE:
|
|
if( m_iSelection >= 0 ) {
|
|
DoToggleExpansion ( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by DoToggleExpansion
|
|
}
|
|
break;
|
|
|
|
case VK_MULTIPLY:
|
|
if ( m_iSelection >= 0) {
|
|
ExpandAll( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by ExpandAll
|
|
}
|
|
break;
|
|
|
|
case VK_DIVIDE:
|
|
if ( m_iSelection >= 0) {
|
|
CollapseAll( m_iSelection );
|
|
iOldTopLine = m_iTopLine; // Scroll is handled by CollapseAll
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Default();
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_iSelection = m_iFocus;
|
|
|
|
SetScrollPos ( SB_VERT, m_iTopLine );
|
|
|
|
if ( m_iSelection < m_iTopLine && m_iSelection >= 0) {
|
|
m_iTopLine = m_iSelection;
|
|
}
|
|
if ( m_iSelection > ( m_iTopLine + m_iPaintLines - 2 ) ) {
|
|
m_iTopLine = m_iSelection - (m_iPaintLines - 2);
|
|
}
|
|
|
|
BOOL bRepaint = FALSE;
|
|
|
|
int iDiff = iOldTopLine - m_iTopLine;
|
|
if ( iDiff != 0 )
|
|
{
|
|
ScrollWindow ( 0, m_itemHeight * iDiff );
|
|
bRepaint = TRUE;
|
|
}
|
|
|
|
if ( m_iSelection != iOldSel )
|
|
{
|
|
InvalidateLine(m_iSelection);
|
|
InvalidateLine(iOldSel);
|
|
UINT flags = 0;
|
|
if (GetKeyState(VK_SHIFT)&0x8000)
|
|
flags |= MK_SHIFT;
|
|
if( m_iSelection >= 0 )
|
|
SelectItem ( m_iSelection, OUTLINER_KEYDOWN, flags );
|
|
KillTimer(ID_OUTLINER_TIMER);
|
|
|
|
bRepaint = TRUE;
|
|
}
|
|
|
|
if (bRepaint)
|
|
UpdateWindow ( );
|
|
|
|
Default();
|
|
}
|
|
|
|
void COutliner::OnSysColorChange ( )
|
|
{
|
|
|
|
CWnd::OnSysColorChange ( );
|
|
if (m_pIImage)
|
|
m_pIImage->ReInitialize();
|
|
m_pIUserImage->ReInitialize();
|
|
Invalidate ( );
|
|
}
|
|
|
|
UINT COutliner::OnGetDlgCode( )
|
|
{
|
|
return DLGC_WANTARROWS;
|
|
}
|
|
|
|
void COutliner::OnKillFocus ( CWnd * pNewWnd )
|
|
{
|
|
CWnd::OnKillFocus ( pNewWnd );
|
|
if (m_iSelection >= 0)
|
|
for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
|
|
if (IsSelected(i))
|
|
InvalidateLine(i);
|
|
|
|
((COutlinerParent*)GetParent())->UpdateFocusFrame();
|
|
}
|
|
|
|
void COutliner::OnSetFocus ( CWnd * pOldWnd )
|
|
{
|
|
Default();
|
|
|
|
if (m_iSelection >= 0)
|
|
for (int i =0; i < (m_iTopLine+m_iPaintLines); i++)
|
|
if (IsSelected(i))
|
|
InvalidateLine(i);
|
|
|
|
((COutlinerParent*)GetParent())->UpdateFocusFrame();
|
|
}
|
|
|
|
void COutliner::SetTotalLines( int iLines )
|
|
{
|
|
m_iTotalLines = iLines;
|
|
if (m_iTopLine > m_iTotalLines) {
|
|
m_iTopLine = m_iTotalLines;
|
|
}
|
|
EnableScrollBars();
|
|
}
|
|
|
|
void COutliner::EnableScrollBars ( void )
|
|
{
|
|
if (m_iTotalLines >= m_iPaintLines) {
|
|
ShowScrollBar(SB_VERT);
|
|
#ifdef WIN32
|
|
SCROLLINFO ScrollInfo;
|
|
ScrollInfo.cbSize = sizeof(SCROLLINFO);
|
|
ScrollInfo.fMask = SIF_PAGE|SIF_RANGE|SIF_POS;
|
|
ScrollInfo.nMin = 0;
|
|
ScrollInfo.nMax = m_iTotalLines - 1;
|
|
ScrollInfo.nPage = m_iPaintLines - 1;
|
|
ScrollInfo.nPos = m_iTopLine;
|
|
SetScrollInfo(SB_VERT,&ScrollInfo, TRUE);
|
|
#else
|
|
SetScrollPos( SB_VERT, m_iTopLine );
|
|
SetScrollRange(SB_VERT,0,(m_iTotalLines - m_iPaintLines)+1, TRUE);
|
|
#endif
|
|
} else {
|
|
if (m_iTopLine > 0) {
|
|
m_iTopLine = 0;
|
|
Invalidate();
|
|
}
|
|
ShowScrollBar ( SB_VERT, FALSE );
|
|
}
|
|
}
|
|
|
|
void COutliner::ScrollIntoView( int iVisible )
|
|
{
|
|
if (iVisible != -1) {
|
|
int iOldTop = m_iTopLine;
|
|
CRect rect;
|
|
GetClientRect(&rect);
|
|
int iAdjust = ((rect.Height() - ((m_iPaintLines-1)*m_itemHeight))+2)/m_itemHeight;
|
|
if (iAdjust == 0)
|
|
iAdjust = 1;
|
|
else
|
|
iAdjust = 0;
|
|
|
|
if ( ( iVisible < m_iTopLine ) ||
|
|
( iVisible > ((m_iTopLine + m_iPaintLines) - iAdjust))) {
|
|
|
|
m_iTopLine = iVisible - (m_iPaintLines/2);
|
|
if ( m_iTopLine < 0 )
|
|
m_iTopLine = 0;
|
|
Invalidate ( );
|
|
}
|
|
else if (iVisible == ((m_iTopLine+m_iPaintLines)-iAdjust)) {
|
|
m_iTopLine++;
|
|
Invalidate();
|
|
}
|
|
UpdateWindow( );
|
|
SetScrollPos( SB_VERT, m_iTopLine );
|
|
}
|
|
}
|
|
|
|
void COutliner::EnsureVisible( int iVisible )
|
|
{
|
|
if (iVisible != -1) {
|
|
int iOldTop = m_iTopLine;
|
|
if (iVisible < m_iTopLine) {
|
|
m_iTopLine = iVisible;
|
|
} else if (iVisible >= (m_iTopLine + m_iPaintLines - 1)) {
|
|
m_iTopLine = iVisible - m_iPaintLines + 2;
|
|
} else {
|
|
return;
|
|
}
|
|
int iDelta = iOldTop - m_iTopLine;
|
|
|
|
ScrollWindow( 0, m_itemHeight * iDelta );
|
|
UpdateWindow( );
|
|
SetScrollPos( SB_VERT, m_iTopLine );
|
|
}
|
|
}
|
|
|
|
void COutliner::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
|
|
{
|
|
int iOldTopLine = m_iTopLine;
|
|
switch ( nSBCode )
|
|
{
|
|
case SB_BOTTOM:
|
|
m_iTopLine = m_iTotalLines - (m_iPaintLines - 2);
|
|
break;
|
|
case SB_LINEDOWN:
|
|
if ( m_iTopLine + ( m_iPaintLines - 1 ) < m_iTotalLines + 1 )
|
|
m_iTopLine++;
|
|
break;
|
|
case SB_LINEUP:
|
|
if ( m_iTopLine )
|
|
m_iTopLine--;
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
if ( m_iTopLine + ( m_iPaintLines - 1 ) < m_iTotalLines )
|
|
m_iTopLine += ( m_iPaintLines - 1 );
|
|
break;
|
|
case SB_PAGEUP:
|
|
m_iTopLine -= (m_iPaintLines - 1);
|
|
break;
|
|
case SB_THUMBPOSITION:
|
|
m_iTopLine = nPos;
|
|
break;
|
|
case SB_THUMBTRACK:
|
|
m_iTopLine = nPos;
|
|
break;
|
|
case SB_TOP:
|
|
m_iTopLine = 0;
|
|
break;
|
|
}
|
|
|
|
if ( m_iTopLine < 0 )
|
|
m_iTopLine = 0;
|
|
|
|
int iDiff = iOldTopLine - m_iTopLine;
|
|
if ( iDiff != 0 )
|
|
{
|
|
ScrollWindow ( 0, m_itemHeight * iDiff );
|
|
UpdateWindow ( );
|
|
}
|
|
|
|
SetScrollPos ( SB_VERT, m_iTopLine );
|
|
Default();
|
|
}
|
|
|
|
BOOL COutliner::ViewerHasFocus ( )
|
|
{
|
|
return ( GetFocus ( ) == this );
|
|
}
|
|
|
|
void COutliner::DoToggleExpansion( int iLine )
|
|
{
|
|
int iDelta = ToggleExpansion( iLine );
|
|
if ( iDelta > 0 ) {
|
|
iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
|
|
EnsureVisible( iLine + iDelta );
|
|
}
|
|
}
|
|
|
|
|
|
void COutliner::DoExpand( int iLine )
|
|
{
|
|
int iDelta = Expand( iLine );
|
|
if ( iDelta > 0 ) {
|
|
iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
|
|
EnsureVisible( iLine + iDelta );
|
|
}
|
|
}
|
|
|
|
void COutliner::DoCollapse( int iLine )
|
|
{
|
|
Collapse( iLine );
|
|
}
|
|
|
|
int COutliner::DoExpandAll( int iLine )
|
|
{
|
|
int iDelta = 0;
|
|
int iDepth = GetDepth( iLine );
|
|
iDelta += Expand(iLine);
|
|
|
|
for (int i = iLine + 1; GetDepth(i) > iDepth; i++)
|
|
iDelta += Expand(i);
|
|
|
|
if ( iDelta > 0 ) {
|
|
iDelta = iDelta > m_iPaintLines - 2 ? m_iPaintLines - 2 : iDelta;
|
|
EnsureVisible( iLine + iDelta );
|
|
}
|
|
return iDelta;
|
|
}
|
|
|
|
int COutliner::DoCollapseAll( int iLine )
|
|
{
|
|
int iDelta = 0;
|
|
int iDepth = GetDepth( iLine );
|
|
int i = iLine;
|
|
while ((i + 1) < m_iTotalLines && GetDepth(i + 1) > iDepth)
|
|
i++;
|
|
|
|
while (i >= iLine) {
|
|
iDelta += Collapse(i);
|
|
i--;
|
|
}
|
|
return iDelta;
|
|
}
|
|
|
|
int COutliner::GetPipeIndex (void *pData, int iDepth, OutlinerAncestorInfo * pAncestor )
|
|
{
|
|
int iTranslated = TranslateIconFolder(pData);
|
|
switch ( iTranslated )
|
|
{
|
|
case OUTLINER_OPENFOLDER:
|
|
case OUTLINER_CLOSEDFOLDER:
|
|
|
|
if ( iTranslated == OUTLINER_OPENFOLDER )
|
|
{
|
|
if ( pAncestor->has_prev && pAncestor->has_next )
|
|
return IDX_OPENMIDDLEPARENT;
|
|
else if ( pAncestor->has_prev )
|
|
return IDX_OPENBOTTOMPARENT;
|
|
else if ( pAncestor->has_next && iDepth )
|
|
return IDX_OPENMIDDLEPARENT;
|
|
else if ( pAncestor->has_next )
|
|
return IDX_OPENTOPPARENT;
|
|
else if ( iDepth )
|
|
return IDX_OPENBOTTOMPARENT;
|
|
else
|
|
return IDX_OPENSINGLEPARENT;
|
|
}
|
|
else
|
|
{
|
|
if ( pAncestor->has_prev && pAncestor->has_next )
|
|
return IDX_CLOSEDMIDDLEPARENT;
|
|
else if ( pAncestor->has_prev )
|
|
return IDX_CLOSEDBOTTOMPARENT;
|
|
else if ( pAncestor->has_next && iDepth )
|
|
return IDX_CLOSEDMIDDLEPARENT;
|
|
else if ( pAncestor->has_next )
|
|
return IDX_CLOSEDTOPPARENT;
|
|
else if ( iDepth )
|
|
return IDX_CLOSEDBOTTOMPARENT;
|
|
else
|
|
return IDX_CLOSEDSINGLEPARENT;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
if ( pAncestor->has_prev && pAncestor->has_next )
|
|
return IDX_MIDDLEITEM;
|
|
else if ( pAncestor->has_prev )
|
|
return IDX_BOTTOMITEM;
|
|
else if ( pAncestor->has_next && iDepth )
|
|
return IDX_MIDDLEITEM;
|
|
else if ( pAncestor->has_next )
|
|
return IDX_TOPITEM;
|
|
else if ( iDepth )
|
|
return IDX_BOTTOMITEM;
|
|
break;
|
|
|
|
}
|
|
return IDX_EMPTYITEM;
|
|
}
|
|
|
|
void COutliner::RectFromLine ( int iLineNo, LPRECT lpRect, LPRECT lpOutRect )
|
|
{
|
|
::SetRect ( lpOutRect,
|
|
0, m_itemHeight * iLineNo,
|
|
lpRect->right, m_itemHeight * iLineNo + m_itemHeight );
|
|
}
|
|
|
|
void COutliner::EraseLine ( int iLineNo, HDC hdc, LPRECT lpWinRect )
|
|
{
|
|
if ( iLineNo >= 0 ) {
|
|
RECT rect;
|
|
RectFromLine ( iLineNo, lpWinRect, &rect );
|
|
::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
|
|
}
|
|
}
|
|
|
|
|
|
int COutliner::DrawPipes ( int iLineNo, int iColNo, int offset, HDC hdc, void * pLineData )
|
|
{
|
|
int iImageWidth = GetIndentationWidth();
|
|
int iMaxX = offset + m_pColumn[ iColNo ]->iCol;
|
|
int idx;
|
|
|
|
int iDepth;
|
|
uint32 flags;
|
|
OutlinerAncestorInfo * pAncestor;
|
|
GetTreeInfo ( m_iTopLine + iLineNo, &flags, &iDepth, &pAncestor );
|
|
|
|
RECT rect;
|
|
rect.left = offset;
|
|
rect.right = rect.left + iImageWidth;
|
|
rect.top = iLineNo * m_itemHeight;
|
|
rect.bottom = rect.top + m_itemHeight;
|
|
|
|
if ( m_bHasPipes ) {
|
|
for ( int i = 0; i < iDepth; i++ ) {
|
|
if ( rect.right <= iMaxX ) {
|
|
if ( pAncestor && pAncestor[ i ].has_next ) {
|
|
m_pIImage->DrawImage( IDX_VERTPIPE, rect.left, rect.top, hdc, FALSE );
|
|
} else {
|
|
::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
|
|
}
|
|
}
|
|
rect.left += iImageWidth;
|
|
rect.right += iImageWidth;
|
|
}
|
|
|
|
if ( rect.right <= iMaxX ) {
|
|
idx = 0;
|
|
if ( pAncestor ) {
|
|
idx = GetPipeIndex ( pLineData, iDepth, &pAncestor[iDepth] );
|
|
}
|
|
if ( idx ) {
|
|
m_pIImage->DrawImage( idx, rect.left, rect.top, hdc, FALSE );
|
|
} else {
|
|
::FillRect(hdc, &rect, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
|
|
}
|
|
}
|
|
rect.left += iImageWidth;
|
|
rect.right += iImageWidth;
|
|
}
|
|
if ( rect.right <= iMaxX ) {
|
|
idx = TranslateIcon (pLineData);
|
|
m_pIUserImage->DrawImage ( idx, rect.left, rect.top, hdc, FALSE );
|
|
}
|
|
return rect.right;
|
|
}
|
|
|
|
void COutliner::DrawColumnText ( HDC hdc, LPRECT lpColumnRect, LPCTSTR lpszString,
|
|
CropType_t cropping, AlignType_t alignment )
|
|
{
|
|
if (!(lpColumnRect->right - lpColumnRect->left))
|
|
return;
|
|
ASSERT(lpszString);
|
|
int iLength = _tcslen(lpszString);
|
|
if (!iLength)
|
|
return;
|
|
|
|
UINT dwDTFormat = DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
|
|
switch (alignment) {
|
|
case AlignCenter:
|
|
dwDTFormat |= DT_CENTER;
|
|
break;
|
|
case AlignRight:
|
|
dwDTFormat |= DT_RIGHT;
|
|
break;
|
|
case AlignLeft:
|
|
default:
|
|
dwDTFormat |= DT_LEFT;
|
|
}
|
|
|
|
UINT dwMoreFormat = 0;
|
|
switch (cropping) {
|
|
case CropCenter:
|
|
dwMoreFormat |= WFE_DT_CROPCENTER;
|
|
break;
|
|
case CropLeft:
|
|
dwMoreFormat |= WFE_DT_CROPLEFT;
|
|
break;
|
|
case CropRight:
|
|
default:
|
|
dwMoreFormat |= WFE_DT_CROPRIGHT;
|
|
break;
|
|
}
|
|
|
|
RECT textRect = *lpColumnRect;
|
|
// Adjust the text rectangle for the left and right margins
|
|
textRect.left += COL_LEFT_MARGIN;
|
|
textRect.right -= COL_LEFT_MARGIN;
|
|
|
|
WFE_DrawTextEx( m_iCSID, hdc, (LPTSTR) lpszString, iLength, &textRect, dwDTFormat, dwMoreFormat );
|
|
}
|
|
|
|
void COutliner::PaintColumn ( int iLineNo, int iColumn, LPRECT lpColumnRect,
|
|
HDC hdc, void * pLineData )
|
|
{
|
|
if (iColumn < m_iVisColumns) {
|
|
LPCTSTR lpsz = GetColumnText (m_pColumn[ iColumn ]->iCommand,pLineData);
|
|
if ( !RenderData( m_pColumn[iColumn]->iCommand, CRect(lpColumnRect),
|
|
*CDC::FromHandle( hdc ), lpsz) ) {
|
|
if (lpsz) {
|
|
DrawColumnText ( hdc, lpColumnRect, lpsz,
|
|
m_pColumn[ iColumn ]->cropping,
|
|
m_pColumn[ iColumn ]->alignment );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutliner::PaintLine ( int iLineNo, HDC hdc, LPRECT lpPaintRect )
|
|
{
|
|
void * pLineData;
|
|
int iImageWidth = GetIndentationWidth();
|
|
CRect WinRect;
|
|
GetClientRect(&WinRect);
|
|
|
|
int y = m_itemHeight * iLineNo;
|
|
|
|
int iColumn, offset;
|
|
CRect rectColumn, rectInter;
|
|
|
|
rectColumn.top = y;
|
|
rectColumn.bottom = y + m_itemHeight;
|
|
|
|
if ( !( pLineData = AcquireLineData( iLineNo + m_iTopLine )) ) {
|
|
EraseLine ( iLineNo, hdc, lpPaintRect );
|
|
if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)) {
|
|
rectColumn.left = WinRect.left;
|
|
rectColumn.right = WinRect.right;
|
|
DrawFocusRect ( hdc, &rectColumn );
|
|
}
|
|
return;
|
|
}
|
|
|
|
HFONT hOldFont =(HFONT) ::SelectObject ( hdc, GetLineFont ( pLineData ) );
|
|
|
|
for ( iColumn = offset = 0; iColumn < m_iVisColumns; iColumn++ )
|
|
{
|
|
rectColumn.left = offset;
|
|
rectColumn.right = offset + m_pColumn[ iColumn ]->iCol;
|
|
|
|
if ( rectInter.IntersectRect ( &rectColumn, lpPaintRect ) ) {
|
|
::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
|
|
//if this is the image column and it also has text in it then call DrawPipes
|
|
// but if it's only an image, don't call DrawPipes.
|
|
if ( m_pColumn[ iColumn ]->iCommand == m_idImageCol && !m_bHasImageOnlyColumn ) {
|
|
rectColumn.left = DrawPipes ( iLineNo, iColumn, offset, hdc, pLineData );
|
|
rectColumn.left += OUTLINE_TEXT_OFFSET;
|
|
}
|
|
PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData );
|
|
}
|
|
|
|
offset += m_pColumn[ iColumn ]->iCol;
|
|
}
|
|
|
|
rectColumn.left = offset;
|
|
rectColumn.right = WinRect.right;
|
|
|
|
::FillRect(hdc, &rectColumn, (HBRUSH) GetCurrentObject(hdc, OBJ_BRUSH));
|
|
PaintColumn ( iLineNo, iColumn, rectColumn, hdc, pLineData );
|
|
|
|
rectColumn.left = WinRect.left;
|
|
rectColumn.right = WinRect.right;
|
|
|
|
// if we are dragging we and we don't highlight we need to draw the drag line
|
|
if(m_iDragSelection == m_iTopLine + iLineNo && !HighlightIfDragging())
|
|
PaintDragLine(hdc, rectColumn);
|
|
|
|
if (ViewerHasFocus() && HasFocus(iLineNo + m_iTopLine)){
|
|
DrawFocusRect ( hdc, &rectColumn );
|
|
}
|
|
|
|
::SelectObject ( hdc, hOldFont );
|
|
ReleaseLineData ( pLineData );
|
|
}
|
|
|
|
void COutliner::PaintDragLine(HDC hdc, CRect &rectColumn)
|
|
{
|
|
|
|
}
|
|
|
|
BOOL COutliner::IsSelected ( int iLineNo )
|
|
{
|
|
return ( iLineNo == m_iSelection );
|
|
}
|
|
|
|
BOOL COutliner::HasFocus ( int iLineNo )
|
|
{
|
|
return ( iLineNo == m_iFocus );
|
|
}
|
|
|
|
BOOL COutliner::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
|
|
{
|
|
if (!CWnd::OnSetCursor( pWnd, nHitTest, message )) {
|
|
SetCursor ( ::LoadCursor( NULL, IDC_ARROW ) );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void COutliner::OnPaint ( )
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
CPaintDC pdc ( this );
|
|
|
|
HBRUSH hRegBrush = ::CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
|
|
HPEN hRegPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_WINDOW ) );
|
|
HBRUSH hHighBrush = ::CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
|
|
HPEN hHighPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_HIGHLIGHT ) );
|
|
|
|
HBRUSH hOldBrush = (HBRUSH) pdc.SelectObject ( hRegBrush );
|
|
HPEN hOldPen = (HPEN) pdc.SelectObject ( hRegPen );
|
|
COLORREF cOldText = pdc.SetTextColor ( GetSysColor ( COLOR_WINDOWTEXT ) );
|
|
COLORREF cOldBk = pdc.SetBkColor ( GetSysColor ( COLOR_WINDOW ) );
|
|
|
|
int i;
|
|
for ( i = pdc.m_ps.rcPaint.top / m_itemHeight;
|
|
i < ( pdc.m_ps.rcPaint.bottom / m_itemHeight ) + 1; i++ ) {
|
|
int index = m_iTopLine + i;
|
|
|
|
if ( ( IsSelected( index ) && ViewerHasFocus () && m_iDragSelection == -1 ) ||
|
|
(( index == m_iDragSelection ) && HighlightIfDragging()) ) {
|
|
pdc.SelectObject ( hHighBrush );
|
|
pdc.SelectObject ( hHighPen );
|
|
pdc.SetTextColor ( GetSysColor ( COLOR_HIGHLIGHTTEXT ) );
|
|
pdc.SetBkColor ( GetSysColor ( COLOR_HIGHLIGHT ) );
|
|
m_pIImage->UseHighlight ( );
|
|
m_pIUserImage->UseHighlight( );
|
|
|
|
PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint );
|
|
|
|
pdc.SetTextColor ( GetSysColor ( COLOR_WINDOWTEXT ) );
|
|
pdc.SetBkColor ( GetSysColor ( COLOR_WINDOW ) );
|
|
pdc.SelectObject ( hRegBrush);
|
|
pdc.SelectObject ( hRegPen );
|
|
m_pIImage->UseNormal( );
|
|
m_pIUserImage->UseNormal( );
|
|
}
|
|
else
|
|
PaintLine ( i, pdc.m_hDC, &pdc.m_ps.rcPaint );
|
|
|
|
if ( !ViewerHasFocus() && IsSelected( m_iTopLine + i ) ) {
|
|
RECT rcLine;
|
|
RectFromLine( i, &rcClient, &rcLine);
|
|
DrawFocusRect ( pdc.m_hDC, &rcLine );
|
|
}
|
|
}
|
|
|
|
pdc.SetTextColor ( cOldText );
|
|
pdc.SetBkColor ( cOldBk );
|
|
pdc.SelectObject ( hOldPen );
|
|
pdc.SelectObject ( hOldBrush );
|
|
|
|
VERIFY(DeleteObject( hRegBrush ));
|
|
VERIFY(DeleteObject( hRegPen ));
|
|
VERIFY(DeleteObject( hHighBrush ));
|
|
VERIFY(DeleteObject( hHighPen ));
|
|
}
|
|
|
|
int COutliner::OnCreate ( LPCREATESTRUCT lpCreateStruct )
|
|
{
|
|
int iRetVal = CWnd::OnCreate ( lpCreateStruct );
|
|
|
|
m_pDropTarget = CreateDropTarget();
|
|
|
|
m_pDropTarget->Register(this);
|
|
InitializeClipFormats ( );
|
|
|
|
SetCSID(INTL_DefaultWinCharSetID(0));
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
COutlinerDropTarget* COutliner::CreateDropTarget()
|
|
{
|
|
return new COutlinerDropTarget(this);
|
|
}
|
|
|
|
void COutliner::SetCSID(int csid)
|
|
{
|
|
CClientDC pdc ( this );
|
|
LOGFONT lf;
|
|
|
|
m_iCSID = csid;
|
|
|
|
if (m_hRegFont) {
|
|
theApp.ReleaseAppFont(m_hRegFont);
|
|
}
|
|
if (m_hBoldFont) {
|
|
theApp.ReleaseAppFont(m_hBoldFont);
|
|
}
|
|
if (m_hItalFont) {
|
|
theApp.ReleaseAppFont(m_hItalFont);
|
|
}
|
|
|
|
memset(&lf,0,sizeof(LOGFONT));
|
|
lf.lfPitchAndFamily = FF_SWISS;
|
|
lf.lfCharSet = IntlGetLfCharset(csid);
|
|
if ((csid == CS_LATIN1)
|
|
|| (csid == CS_UTF8)
|
|
)
|
|
_tcscpy(lf.lfFaceName, "MS Sans Serif");
|
|
else
|
|
_tcscpy(lf.lfFaceName, IntlGetUIPropFaceName(csid));
|
|
lf.lfHeight = -MulDiv(9,pdc.GetDeviceCaps(LOGPIXELSY), 72);
|
|
m_hRegFont = theApp.CreateAppFont( lf );
|
|
lf.lfWeight = 700;
|
|
m_hBoldFont = theApp.CreateAppFont( lf );
|
|
lf.lfWeight = 0;
|
|
lf.lfItalic = TRUE;
|
|
m_hItalFont = theApp.CreateAppFont( lf );
|
|
TEXTMETRIC tm;
|
|
|
|
HFONT pOldFont = (HFONT) pdc.SelectObject ( m_hBoldFont );
|
|
pdc.GetTextMetrics ( &tm );
|
|
pdc.SelectObject(pOldFont);
|
|
m_cxChar = tm.tmAveCharWidth;
|
|
m_cyChar = tm.tmHeight + tm.tmExternalLeading;
|
|
m_itemHeight = m_cyChar;
|
|
if ( m_pIImage )
|
|
InitializeItemHeight(max(m_pIImage->GetImageHeight(),m_itemHeight));
|
|
else InitializeItemHeight(m_itemHeight);
|
|
|
|
Invalidate();
|
|
|
|
m_pTip->SetCSID(m_iCSID);
|
|
}
|
|
|
|
|
|
int COutliner::LineFromPoint (POINT point)
|
|
{
|
|
int iLine = m_iTopLine + (point.y / m_itemHeight);
|
|
|
|
// Figure out which portion of the line the point is on.
|
|
int iDiff = point.y - ((iLine - m_iTopLine) *m_itemHeight);
|
|
|
|
m_iOldLineHalf = m_iDragSelectionLineHalf;
|
|
m_iOldLineThird = m_iDragSelectionLineThird;
|
|
|
|
m_iDragSelectionLineHalf = (iDiff <= m_itemHeight / 2) ? 1 : 2;
|
|
m_iDragSelectionLineThird = (iDiff <= m_itemHeight / 3) ? 1 : (iDiff <= 2 * (m_itemHeight/3)) ? 2 : 3;
|
|
|
|
if(m_iTopLine !=0)
|
|
int i =0;
|
|
m_bDragSectionChanged = (m_iOldLineHalf != m_iDragSelectionLineHalf || m_iOldLineThird !=m_iDragSelectionLineThird);
|
|
|
|
return ( iLine );
|
|
}
|
|
|
|
DROPEFFECT COutliner::DropSelect (int iLineNo, COleDataObject *object )
|
|
{
|
|
if (iLineNo >= m_iTotalLines)
|
|
return DROPEFFECT_NONE;
|
|
else if (iLineNo == m_iDragSelection && !m_bDragSectionChanged)
|
|
return DROPEFFECT_MOVE;
|
|
|
|
if (m_iDragSelection != -1)
|
|
InvalidateLine (m_iDragSelection);
|
|
|
|
m_iDragSelection = iLineNo;
|
|
InvalidateLine (m_iDragSelection);
|
|
|
|
return DROPEFFECT_MOVE;
|
|
}
|
|
|
|
void COutliner::EndDropSelect(void)
|
|
{
|
|
if (m_iDragSelection != -1) {
|
|
m_iDragSelection = -1;
|
|
m_iDragSelectionLineHalf = -1;
|
|
m_iDragSelectionLineThird = -1;
|
|
m_bDragSectionChanged = FALSE;
|
|
Invalidate();
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
COleDataSource *COutliner::GetDataSource(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void COutliner::InitiateDragDrop(void)
|
|
{
|
|
m_bDraggingData = TRUE;
|
|
COleDataSource * pDataSource = GetDataSource();
|
|
if ( pDataSource) {
|
|
DROPEFFECT res = pDataSource->DoDragDrop
|
|
(DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_SCROLL);
|
|
pDataSource->Empty();
|
|
delete pDataSource;
|
|
}
|
|
m_bDraggingData = FALSE;
|
|
}
|
|
|
|
BOOL COutliner::RecognizedFormat (COleDataObject * pDataObject)
|
|
{
|
|
CLIPFORMAT * pFormatList = GetClipFormatList();
|
|
if (pFormatList != NULL) {
|
|
while (*pFormatList) {
|
|
if (pDataObject->IsDataAvailable(*pFormatList))
|
|
return TRUE;
|
|
pFormatList++;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void COutliner::AcceptDrop(int iLineNo, class COleDataObject *pDataObject,
|
|
DROPEFFECT dropEffect)
|
|
{
|
|
|
|
}
|
|
|
|
CLIPFORMAT * COutliner::GetClipFormatList(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void COutliner::OnSelChanged()
|
|
{
|
|
}
|
|
|
|
void COutliner::OnSelDblClk()
|
|
{
|
|
}
|
|
|
|
#if defined(XP_WIN32) && _MSC_VER >= 1100
|
|
LONG COutliner::OnHackedMouseWheel(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return(OnMouseWheel(wParam << 16, lParam));
|
|
}
|
|
|
|
LONG COutliner::OnMouseWheel(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Increase the delta.
|
|
m_iWheelDelta += MOUSEWHEEL_DELTA(wParam, lParam);
|
|
|
|
// Number of lines to scroll.
|
|
UINT uScroll = intelli.ScrollLines();
|
|
|
|
// Direction.
|
|
BOOL bForward = TRUE;
|
|
if(m_iWheelDelta < 0) {
|
|
bForward = FALSE;
|
|
}
|
|
|
|
// Scroll bar code to use.
|
|
UINT uSBCode = SB_LINEUP;
|
|
|
|
if(m_iWheelDelta / WHEEL_DELTA) {
|
|
if(uScroll == WHEEL_PAGESCROLL) {
|
|
if(bForward) {
|
|
uSBCode = SB_PAGEUP;
|
|
}
|
|
else {
|
|
uSBCode = SB_PAGEDOWN;
|
|
}
|
|
uScroll = 1;
|
|
}
|
|
else {
|
|
if(bForward) {
|
|
uSBCode = SB_LINEUP;
|
|
}
|
|
else {
|
|
uSBCode = SB_LINEDOWN;
|
|
}
|
|
}
|
|
|
|
// Take off scroll increment.
|
|
UINT uLoops = 0;
|
|
while(m_iWheelDelta / WHEEL_DELTA) {
|
|
if(bForward) {
|
|
m_iWheelDelta -= WHEEL_DELTA;
|
|
}
|
|
else {
|
|
m_iWheelDelta += WHEEL_DELTA;
|
|
}
|
|
uLoops++;
|
|
}
|
|
|
|
// Do it.
|
|
if(uLoops) {
|
|
OnVScroll(uSBCode, 0, NULL);
|
|
}
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// rhp - Added for QA Partner hooks - NO NEED TO I18N/L10N SINCE THIS
|
|
// IS FOR QA WORK ONLY!!!
|
|
//
|
|
#define NULL_STRING "<Null>"
|
|
|
|
LPCSTR
|
|
NullIt(LPCTSTR inVar)
|
|
{
|
|
if (!inVar)
|
|
return NULL_STRING;
|
|
|
|
if (inVar[0] == '\0')
|
|
return NULL_STRING;
|
|
|
|
return inVar;
|
|
}
|
|
|
|
// This is the result of a WM_COPYDATA message. This will be used to send requests
|
|
// into Communicator to get data out of Outliner objects as well as drive the
|
|
// application for automated testing. The return codes of these call will either be
|
|
// the data/number asked for or just a status of processing the request and getting
|
|
// the information into the share memory segment.
|
|
//
|
|
// The description of the parameters coming into this call are:
|
|
//
|
|
// wParam = (WPARAM) (HWND) hwnd; // handle of sending window
|
|
// lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data
|
|
//
|
|
// typedef struct tagCOPYDATASTRUCT { // cds
|
|
// DWORD dwData; // the ID of the request
|
|
// DWORD cbData; // the size of the argument
|
|
// PVOID lpData; // the data (i.e. the pointer/name of shared mem)
|
|
// } COPYDATASTRUCT;
|
|
//
|
|
// The lpData will be NULL for all Win32 calls and it will be a pointer to
|
|
// the (CSharedData *) structure to fill on Win16
|
|
//
|
|
// Returns: This is call specific. For calls that only return numeric values,
|
|
// the return code is results. For calls that return buffers of data, this is a
|
|
// status code witht the following meaning:
|
|
//
|
|
// 0 - Problem with the processing.
|
|
// 1 - Everything is ok.
|
|
//
|
|
LONG COutliner::OnProcessOLQAHook(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CSharedData *memChunk = NULL;
|
|
|
|
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam;
|
|
if (lParam == NULL)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
TRACE("OLQAHook Message ID = %d\n", pcds->dwData);
|
|
switch (pcds->dwData)
|
|
{
|
|
case QA_OLGETCOUNT:
|
|
return(GetTotalLines());
|
|
break;
|
|
|
|
case QA_OLGETVISIBLECOUNT:
|
|
return(GetVisibleColumns());
|
|
break;
|
|
|
|
case QA_OLGETFOCUSLINE:
|
|
return(GetFocusLine());
|
|
break;
|
|
|
|
case QA_OLGETCOLCOUNT:
|
|
return(GetNumColumns());
|
|
break;
|
|
|
|
// rhp - new code as of 12/2
|
|
case QA_OLGETISCOLLAPSED:
|
|
{
|
|
DWORD *dwPtr;
|
|
|
|
dwPtr = (DWORD *)pcds->lpData;
|
|
return(IsCollapsed( *dwPtr ));
|
|
break;
|
|
}
|
|
|
|
case QA_OLGETNUMCHILDREN:
|
|
{
|
|
DWORD *dwPtr;
|
|
|
|
dwPtr = (DWORD *)pcds->lpData;
|
|
return(GetNumChildren( *dwPtr ));
|
|
break;
|
|
}
|
|
|
|
case QA_OLSCROLLINTOVIEW:
|
|
{
|
|
DWORD *dwPtr;
|
|
|
|
dwPtr = (DWORD *)pcds->lpData;
|
|
ScrollIntoView( *dwPtr );
|
|
return(1);
|
|
}
|
|
|
|
case QA_OLSETFOCUSLINE:
|
|
{
|
|
DWORD *dwPtr;
|
|
|
|
dwPtr = (DWORD *)pcds->lpData;
|
|
SetFocusLine(*dwPtr);
|
|
SelectItem( *dwPtr );
|
|
return (1);
|
|
break;
|
|
}
|
|
case QA_OLGETTEXT:
|
|
{
|
|
#ifdef WIN32
|
|
memChunk = OpenExistingSharedMemory();
|
|
#else
|
|
memChunk = (CSharedData *) pcds->lpData;
|
|
#endif
|
|
if (!memChunk)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
DWORD i;
|
|
DWORD lineNumber = GetFocusLine();
|
|
char workLine[8192];
|
|
DWORD copySize;
|
|
void *pLineData = AcquireLineData ( lineNumber ); // Make this a parameter...
|
|
|
|
memset(workLine, 0, sizeof(workLine));
|
|
for (i=0; i< (DWORD) GetNumColumns(); i++)
|
|
{
|
|
LPCTSTR colText = GetColumnText ( m_pColumn[ i ]->iCommand, pLineData );
|
|
if (!colText)
|
|
continue;
|
|
|
|
lstrcat(workLine, NullIt(m_pColumn[ i ]->pHeader));
|
|
lstrcat(workLine, "=");
|
|
|
|
lstrcat(workLine, NullIt(colText));
|
|
lstrcat(workLine, "|");
|
|
}
|
|
|
|
ReleaseLineData(pLineData);
|
|
|
|
//
|
|
// Make sure we don't do something stupid!
|
|
//
|
|
if (strlen((char *)workLine) < memChunk->m_dwSize)
|
|
{
|
|
copySize = strlen((char *)workLine);
|
|
}
|
|
else
|
|
{
|
|
copySize = memChunk->m_dwSize;
|
|
}
|
|
|
|
strncpy((char *) memChunk->m_buf, (char *)workLine, copySize);
|
|
memChunk->m_buf[copySize] = '\0';
|
|
memChunk->m_dwBytesUsed = copySize + 1;
|
|
|
|
CloseSharedMemory();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
// rhp
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CMSelectOutliner
|
|
|
|
CMSelectOutliner::CMSelectOutliner()
|
|
{
|
|
m_bNoMultiSel = FALSE;
|
|
m_iShiftAnchor = -1;
|
|
m_iIndicesSize = 64;
|
|
m_pIndices = new MSG_ViewIndex[m_iIndicesSize];
|
|
m_iIndicesCount = 0;
|
|
}
|
|
|
|
CMSelectOutliner::~CMSelectOutliner()
|
|
{
|
|
delete [] m_pIndices;
|
|
}
|
|
|
|
|
|
void CMSelectOutliner::ClearSelection()
|
|
{
|
|
int i;
|
|
for (i = 0; i < m_iIndicesCount; i++ ) {
|
|
InvalidateLine(CASTINT(m_pIndices[i]));
|
|
m_pIndices[i] = 0;
|
|
}
|
|
m_iIndicesCount = 0;
|
|
}
|
|
|
|
void CMSelectOutliner::GetSelection( const MSG_ViewIndex *&indices, int &count )
|
|
{
|
|
indices = m_pIndices;
|
|
count = m_iIndicesCount;
|
|
}
|
|
|
|
void CMSelectOutliner::AddSelection( MSG_ViewIndex iSel )
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < m_iIndicesCount; i++) {
|
|
if ( m_pIndices[i] == iSel ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (i >= m_iIndicesSize) {
|
|
// Resize storage array (exponential grow)
|
|
MSG_ViewIndex *tmp = new MSG_ViewIndex[m_iIndicesSize * 2];
|
|
memcpy(tmp, m_pIndices, m_iIndicesSize * sizeof(MSG_ViewIndex));
|
|
delete [] m_pIndices;
|
|
m_pIndices = tmp;
|
|
m_iIndicesSize *= 2;
|
|
}
|
|
if (iSel >= 0 && iSel < (MSG_ViewIndex) m_iTotalLines) {
|
|
m_pIndices[i] = iSel;
|
|
m_iIndicesCount++;
|
|
}
|
|
|
|
InvalidateLine( CASTINT(iSel) );
|
|
}
|
|
|
|
void CMSelectOutliner::RemoveSelection( MSG_ViewIndex iSel )
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0, j = 0; i < m_iIndicesCount; i++) {
|
|
if (m_pIndices[i] == iSel) {
|
|
InvalidateLine( CASTINT(iSel) );
|
|
} else {
|
|
m_pIndices[j] = m_pIndices[i];
|
|
j++;
|
|
}
|
|
}
|
|
m_iIndicesCount = j;
|
|
m_iSelection = -1;
|
|
m_iFocus = -1;
|
|
}
|
|
|
|
void CMSelectOutliner::RemoveSelectionRange( MSG_ViewIndex iSelBegin, MSG_ViewIndex iSelEnd )
|
|
{
|
|
int i, j;
|
|
if ( iSelBegin > iSelEnd ) {
|
|
MSG_ViewIndex tmp;
|
|
tmp = iSelEnd;
|
|
iSelEnd = iSelBegin;
|
|
iSelBegin = tmp;
|
|
}
|
|
for (i = 0, j = 0; i < m_iIndicesCount; i++ ) {
|
|
if (m_pIndices[i] >= iSelBegin && m_pIndices[i] <= iSelEnd) {
|
|
InvalidateLine( CASTINT(m_pIndices[i]) );
|
|
} else {
|
|
m_pIndices[j] = m_pIndices[i];
|
|
j++;
|
|
}
|
|
}
|
|
m_iIndicesCount = j;
|
|
m_iSelection = -1;
|
|
m_iFocus = -1;
|
|
}
|
|
|
|
BOOL CMSelectOutliner::IsSelected ( int iLine )
|
|
{
|
|
int i;
|
|
for (i = 0; i < m_iIndicesCount; i++) {
|
|
if ( (int) m_pIndices[i] == iLine ) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CMSelectOutliner::SelectRange( MSG_ViewIndex iSelBegin, MSG_ViewIndex iSelEnd )
|
|
{
|
|
// WHS - we may want to optimize this
|
|
MSG_ViewIndex i;
|
|
|
|
if ( iSelBegin > iSelEnd ) {
|
|
MSG_ViewIndex tmp;
|
|
tmp = iSelEnd;
|
|
iSelEnd = iSelBegin;
|
|
iSelBegin = tmp;
|
|
}
|
|
|
|
for ( i = iSelBegin; i <= iSelEnd; i++ ) {
|
|
AddSelection(i);
|
|
}
|
|
}
|
|
|
|
BOOL CMSelectOutliner::HandleInsert( MSG_ViewIndex iStart, int32 iCount )
|
|
{
|
|
int i;
|
|
for (i = 0; i < m_iIndicesCount; i++) {
|
|
if ( m_pIndices[i] >= iStart ) {
|
|
m_pIndices[i] += iCount; // Shift over to make room
|
|
}
|
|
}
|
|
if (m_iSelection >= (int) iStart ) {
|
|
m_iSelection += CASTINT(iCount);
|
|
}
|
|
if (m_iFocus >= (int) iStart ) {
|
|
m_iFocus += CASTINT(iCount);
|
|
}
|
|
if (m_iShiftAnchor >= (int) iStart ) {
|
|
m_iShiftAnchor += CASTINT(iCount);
|
|
}
|
|
|
|
m_iTotalLines += CASTINT(iCount);
|
|
|
|
// Invalidate previous line so pipes are drawn correctly
|
|
if ( iStart ) {
|
|
iStart--;
|
|
iCount++;
|
|
}
|
|
InvalidateLines( CASTINT(iStart), CASTINT(m_iTotalLines - iStart + iCount));
|
|
EnableScrollBars();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CMSelectOutliner::HandleDelete( MSG_ViewIndex iStart, int32 iCount )
|
|
{
|
|
BOOL res = FALSE;
|
|
int i, j;
|
|
|
|
for (i = 0, j = 0; i < m_iIndicesCount; i++) {
|
|
if ( m_pIndices[i] >= iStart ) {
|
|
if (m_pIndices[i] < (iStart + iCount)) {
|
|
res = TRUE;
|
|
continue;
|
|
} else {
|
|
m_pIndices[i] -= iCount; // Shift into gap
|
|
}
|
|
}
|
|
m_pIndices[j] = m_pIndices[i];
|
|
j++;
|
|
}
|
|
m_iIndicesCount = j;
|
|
if (m_iSelection >= int(iStart) ) {
|
|
if (m_iSelection < int(iStart + iCount))
|
|
m_iSelection = int(iStart);
|
|
else
|
|
m_iSelection -= CASTINT(iCount);
|
|
|
|
if (m_iSelection >= m_iTotalLines - iCount)
|
|
m_iSelection = CASTINT(m_iTotalLines - iCount - 1);
|
|
|
|
if (m_iSelection < 0 )
|
|
m_iSelection = (m_iTotalLines - iCount) > 0 ? 0 : -1;
|
|
}
|
|
if (m_iFocus >= int(iStart) ) {
|
|
if (m_iFocus < int(iStart + iCount))
|
|
m_iFocus = int(iStart);
|
|
else
|
|
m_iFocus -= CASTINT(iCount);
|
|
|
|
if (m_iFocus >= m_iTotalLines - iCount)
|
|
m_iFocus = CASTINT(m_iTotalLines - iCount - 1);
|
|
|
|
if (m_iFocus < 0)
|
|
m_iFocus = 0;
|
|
}
|
|
if (m_iShiftAnchor >= int(iStart) ) {
|
|
if (m_iShiftAnchor < int(iStart + iCount))
|
|
m_iShiftAnchor = int(iStart);
|
|
else
|
|
m_iShiftAnchor -= CASTINT(iCount);
|
|
|
|
if (m_iShiftAnchor >= m_iTotalLines - iCount)
|
|
m_iShiftAnchor = CASTINT(m_iTotalLines - iCount - 1);
|
|
|
|
if (m_iShiftAnchor < 0)
|
|
m_iShiftAnchor = 0;
|
|
}
|
|
|
|
m_iTotalLines -= CASTINT(iCount);
|
|
|
|
if (!IsSelected(m_iSelection) && (m_iTotalLines > 0))
|
|
AddSelection( m_iSelection );
|
|
|
|
// Invalidate previous line so pipes are drawn correctly
|
|
if ( iStart ) {
|
|
iStart--;
|
|
iCount++;
|
|
}
|
|
InvalidateLines(CASTINT(iStart), CASTINT(m_iTotalLines - iStart + iCount));
|
|
EnableScrollBars();
|
|
|
|
return res;
|
|
}
|
|
|
|
void CMSelectOutliner::HandleScramble()
|
|
{
|
|
ASSERT(0); // nothing we can do.
|
|
}
|
|
|
|
void CMSelectOutliner::PositionHome( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionHome();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::PositionEnd( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionEnd();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::PositionPrevious( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionPrevious();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::PositionNext( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionNext();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::PositionPageDown( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionPageDown();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::PositionPageUp( )
|
|
{
|
|
int iOldFocus = m_iFocus;
|
|
|
|
COutliner::PositionPageUp();
|
|
|
|
if (iOldFocus != m_iFocus ) {
|
|
ClearSelection();
|
|
AddSelection(m_iFocus);
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::SetMultipleSelection(BOOL bMultipleSelection)
|
|
{
|
|
m_bNoMultiSel = !bMultipleSelection;
|
|
}
|
|
|
|
|
|
void CMSelectOutliner::SetTotalLines ( int iLines )
|
|
{
|
|
COutliner::SetTotalLines( iLines );
|
|
}
|
|
|
|
void CMSelectOutliner::SelectItem( int iSel, int mode, UINT flags )
|
|
{
|
|
if ( m_bNoMultiSel ) {
|
|
flags = 0;
|
|
}
|
|
|
|
if ( (iSel >= -1) || (iSel < GetTotalLines()) ) {
|
|
|
|
if ( !(flags & MK_SHIFT) || (m_iShiftAnchor == -1 ) )
|
|
m_iShiftAnchor = iSel;
|
|
|
|
switch ( mode ) {
|
|
case OUTLINER_LBUTTONDOWN:
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection = iSel;
|
|
InvalidateLine( m_iFocus );
|
|
|
|
if ( IsSelected(iSel) ) {
|
|
if ( flags & MK_CONTROL ) {
|
|
m_bClearOnRelease = TRUE;
|
|
} else if ( !( flags & MK_SHIFT) ){
|
|
m_bSelectOnRelease = TRUE;
|
|
}
|
|
} else {
|
|
if ( !(flags & MK_CONTROL) ) {
|
|
ClearSelection();
|
|
}
|
|
}
|
|
|
|
if ( flags & MK_SHIFT ) {
|
|
ClearSelection();
|
|
SelectRange( m_iShiftAnchor, m_iSelection);
|
|
} else {
|
|
AddSelection(m_iSelection);
|
|
}
|
|
break;
|
|
|
|
case OUTLINER_LBUTTONUP:
|
|
if (m_bClearOnRelease) {
|
|
RemoveSelection(iSel);
|
|
}
|
|
if ( m_bSelectOnRelease ) {
|
|
ClearSelection();
|
|
AddSelection(iSel);
|
|
}
|
|
OnSelChanged();
|
|
m_iLastSelected = iSel;
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
break;
|
|
|
|
case 0:
|
|
ASSERT(0);
|
|
|
|
case OUTLINER_KEYDOWN:
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection = iSel;
|
|
InvalidateLine( m_iFocus );
|
|
ClearSelection();
|
|
if ( flags & MK_SHIFT ) {
|
|
SelectRange( m_iShiftAnchor, m_iSelection);
|
|
} else {
|
|
AddSelection(m_iSelection);
|
|
}
|
|
if (m_iLastSelected == -1)
|
|
{
|
|
OnSelChanged();
|
|
m_iLastSelected = m_iSelection;
|
|
}
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
break;
|
|
|
|
case OUTLINER_RBUTTONDOWN:
|
|
if (!IsSelected( iSel )) {
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection = iSel;
|
|
InvalidateLine( m_iFocus );
|
|
ClearSelection();
|
|
AddSelection( m_iSelection );
|
|
OnSelChanged();
|
|
m_iLastSelected = m_iSelection;
|
|
}
|
|
break;
|
|
|
|
case OUTLINER_SET:
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection = iSel;
|
|
InvalidateLine( m_iFocus );
|
|
if (!(flags & MK_CONTROL)) {
|
|
ClearSelection();
|
|
}
|
|
AddSelection(m_iSelection);
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
|
|
case OUTLINER_TIMER:
|
|
OnSelChanged();
|
|
m_iLastSelected = m_iSelection;
|
|
break;
|
|
|
|
case OUTLINER_RETURN:
|
|
if (!IsSelected(iSel)) {
|
|
InvalidateLine( m_iFocus );
|
|
m_iFocus = m_iSelection = iSel;
|
|
InvalidateLine( m_iFocus );
|
|
if (!(flags & MK_CONTROL)) {
|
|
ClearSelection();
|
|
}
|
|
AddSelection(m_iSelection);
|
|
break;
|
|
}
|
|
|
|
case OUTLINER_LBUTTONDBLCLK:
|
|
OnSelDblClk();
|
|
m_bClearOnRelease = FALSE;
|
|
m_bSelectOnRelease = FALSE;
|
|
break;
|
|
|
|
default:
|
|
ASSERT("What kind of garbage are you passing me?" == NULL);
|
|
}
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
void CMSelectOutliner::SelectRange( int iStart, int iEnd, BOOL bNotify )
|
|
{
|
|
if ( iStart == -1 ) {
|
|
ClearSelection();
|
|
} else {
|
|
if (iEnd == -1) {
|
|
iEnd = m_iTotalLines - 1;
|
|
}
|
|
SelectRange( iStart, iEnd );
|
|
}
|
|
if ( bNotify )
|
|
OnSelChanged();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COutlinerDropTarget
|
|
|
|
COutlinerDropTarget::COutlinerDropTarget( COutliner *pOutliner )
|
|
{
|
|
ASSERT(pOutliner);
|
|
m_pOutliner = pOutliner;
|
|
m_dwOldTicks = 0;
|
|
}
|
|
|
|
void COutlinerDropTarget::DragScroll( BOOL bBackwards )
|
|
{
|
|
DWORD dwTicks = GetTickCount();
|
|
if (!dwTicks || (dwTicks - m_dwOldTicks) > (DWORD) m_pOutliner->GetDragHeartbeat()) {
|
|
if (dwTicks) {
|
|
m_pOutliner->OnVScroll(bBackwards ? SB_LINEUP : SB_LINEDOWN, 0, 0);
|
|
m_pOutliner->UpdateWindow();
|
|
}
|
|
m_dwOldTicks = dwTicks;
|
|
}
|
|
}
|
|
|
|
BOOL COutlinerDropTarget::OnDrop(
|
|
CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
|
|
{
|
|
m_dwOldTicks = 0;
|
|
|
|
if(!pDataObject || !m_pOutliner)
|
|
return(FALSE);
|
|
|
|
if (!m_pOutliner->RecognizedFormat(pDataObject))
|
|
return FALSE;
|
|
|
|
m_pOutliner->m_ptHit = point;
|
|
|
|
m_pOutliner->AcceptDrop( m_pOutliner->GetDropLine(), pDataObject, dropEffect);
|
|
m_pOutliner->EndDropSelect();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
DROPEFFECT COutlinerDropTarget::OnDragEnter(
|
|
CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
|
|
{
|
|
DROPEFFECT res = OnDragOver(pWnd, pDataObject, dwKeyState, point);
|
|
|
|
if ( res != DROPEFFECT_NONE) {
|
|
m_pOutliner->Invalidate();
|
|
m_pOutliner->UpdateWindow();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
DROPEFFECT COutlinerDropTarget::OnDragOver(
|
|
CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
|
|
{
|
|
DROPEFFECT effect = DROPEFFECT_NONE;
|
|
|
|
if (m_pOutliner->RecognizedFormat(pDataObject)) {
|
|
RECT rect;
|
|
pWnd->GetClientRect(&rect);
|
|
|
|
if ( point.y < m_pOutliner->m_itemHeight ) {
|
|
DragScroll(TRUE);
|
|
effect |= DROPEFFECT_SCROLL;
|
|
} else if ( point.y > ( rect.bottom - m_pOutliner->m_itemHeight ) ) {
|
|
DragScroll(FALSE);
|
|
effect |= DROPEFFECT_SCROLL;
|
|
} else {
|
|
m_dwOldTicks = 0;
|
|
}
|
|
|
|
m_pOutliner->m_ptHit = point;
|
|
|
|
effect |= m_pOutliner->DropSelect(m_pOutliner->LineFromPoint(point), pDataObject);
|
|
|
|
// Default is to move
|
|
if ( ( effect & DROPEFFECT_MOVE) && (dwKeyState & MK_CONTROL) )
|
|
effect = (effect & ~DROPEFFECT_MOVE) | DROPEFFECT_COPY;
|
|
}
|
|
return effect;
|
|
}
|
|
|
|
void COutlinerDropTarget::OnDragLeave(CWnd* pWnd)
|
|
{
|
|
m_pOutliner->EndDropSelect();
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
DROPEFFECT COutlinerDropTarget::OnDragScroll(
|
|
CWnd* pWnd, DWORD dwKeyState, CPoint point)
|
|
#else
|
|
BOOL COutlinerDropTarget::OnDragScroll(
|
|
CWnd* pWnd, DWORD dwKeyState, CPoint point)
|
|
#endif
|
|
{
|
|
return COleDropTarget::OnDragScroll(pWnd, dwKeyState, point);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COutlinerParent
|
|
|
|
void COutlinerParent::SetOutliner ( COutliner * pOutliner )
|
|
{
|
|
m_pOutliner = pOutliner;
|
|
}
|
|
|
|
void COutlinerParent::InvalidatePusher()
|
|
{
|
|
RECT rect;
|
|
GetClientRect(&rect);
|
|
rect.left = rect.right - m_iPusherWidth;
|
|
rect.bottom = m_iHeaderHeight;
|
|
InvalidateRect(&rect);
|
|
}
|
|
|
|
int COutlinerParent::TestPusher( POINT &pt )
|
|
{
|
|
RECT rect;
|
|
GetClientRect(&rect);
|
|
rect.left = rect.right - m_iPusherWidth;
|
|
rect.bottom = m_iHeaderHeight;
|
|
if (::PtInRect(&rect, pt)) {
|
|
switch(m_iPusherState) {
|
|
case pusherLeft:
|
|
case pusherRight:
|
|
case pusherLeftRight:
|
|
rect.right = rect.left + (rect.right - rect.left) / 2;
|
|
if (::PtInRect(&rect, pt)) {
|
|
return pusherLeft;
|
|
} else {
|
|
return pusherRight;
|
|
}
|
|
}
|
|
}
|
|
return pusherNone;
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(COutlinerParent, CWnd)
|
|
ON_WM_PAINT ( )
|
|
ON_WM_CREATE ( )
|
|
ON_WM_SIZE ( )
|
|
ON_WM_SETFOCUS ( )
|
|
ON_WM_KEYDOWN ( )
|
|
ON_WM_ERASEBKGND ( )
|
|
ON_WM_MOUSEMOVE ( )
|
|
ON_WM_LBUTTONDOWN ( )
|
|
ON_WM_LBUTTONUP ( )
|
|
ON_WM_SETCURSOR ( )
|
|
END_MESSAGE_MAP()
|
|
|
|
class CNSOutlinerParentFactory : public CGenericFactory
|
|
{
|
|
public:
|
|
CNSOutlinerParentFactory();
|
|
~CNSOutlinerParentFactory();
|
|
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj);
|
|
};
|
|
|
|
CNSOutlinerParentFactory::CNSOutlinerParentFactory()
|
|
{
|
|
ApiApiPtr(api);
|
|
api->RegisterClassFactory(APICLASS_OUTLINERPARENT,this);
|
|
}
|
|
|
|
CNSOutlinerParentFactory::~CNSOutlinerParentFactory()
|
|
{
|
|
}
|
|
|
|
STDMETHODIMP CNSOutlinerParentFactory::CreateInstance(
|
|
LPUNKNOWN pUnkOuter,
|
|
REFIID refiid,
|
|
LPVOID * ppvObj)
|
|
{
|
|
COutlinerParent * pParent = new COutlinerParent;
|
|
*ppvObj = (LPVOID)((LPUNKNOWN)pParent);
|
|
return NOERROR;
|
|
}
|
|
|
|
DECLARE_FACTORY(CNSOutlinerParentFactory);
|
|
|
|
COutlinerParent::COutlinerParent ( )
|
|
{
|
|
m_bResizeArea = FALSE;
|
|
m_bResizeColumn = FALSE;
|
|
m_bHeaderSelected = FALSE;
|
|
m_bDraggingHeader = FALSE;
|
|
m_idColHit = 0;
|
|
m_iColHit = -1;
|
|
m_iColLoser = -1;
|
|
m_bHasBorder = FALSE;
|
|
m_bDisableHeaders = FALSE;
|
|
m_bEnableFocusFrame = FALSE;
|
|
m_pOutliner = NULL;
|
|
m_hToolFont = NULL;
|
|
m_hbmDrag = NULL;
|
|
m_hdcDrag = NULL;
|
|
m_iHeaderHeight = 0;
|
|
m_iPusherRgn = pusherNone;
|
|
m_iPusherHit = pusherNone;
|
|
|
|
ApiApiPtr(api);
|
|
m_pUnkImage = api->CreateClassInstance(
|
|
APICLASS_IMAGEMAP,NULL,(APISIGNATURE)IDB_COLUMN);
|
|
m_pUnkImage->QueryInterface(IID_IImageMap,(LPVOID*)&m_pIImage);
|
|
ASSERT(m_pIImage);
|
|
if (!m_pIImage->GetResourceID())
|
|
m_pIImage->Initialize(IDB_COLUMN,8,8);
|
|
}
|
|
|
|
COutlinerParent::~COutlinerParent ( )
|
|
{
|
|
if (m_hToolFont) {
|
|
theApp.ReleaseAppFont(m_hToolFont);
|
|
}
|
|
if ( m_hdcDrag )
|
|
VERIFY(::DeleteDC( m_hdcDrag ));
|
|
if ( m_hbmDrag )
|
|
VERIFY(::DeleteObject( m_hbmDrag ));
|
|
|
|
delete m_pOutliner;
|
|
if (m_pUnkImage) {
|
|
if (m_pIImage)
|
|
m_pUnkImage->Release();
|
|
}
|
|
}
|
|
|
|
BOOL COutlinerParent::ResizeClipCursor()
|
|
{
|
|
CFont *pOldFont = NULL;
|
|
CDC *pDC = m_pOutliner->GetDC();
|
|
if( GetFont() )
|
|
{
|
|
pOldFont = pDC->SelectObject( GetFont() );
|
|
}
|
|
CSize csMinWidth = pDC->GetTextExtent( "W", _tcslen( "W" ) );
|
|
csMinWidth.cx++;
|
|
if( pOldFont )
|
|
{
|
|
pDC->SelectObject( pOldFont );
|
|
}
|
|
m_pOutliner->ReleaseDC( pDC );
|
|
|
|
int iLeft = csMinWidth.cx; //max( m_pOutliner->m_pColumn[m_iColHit]->iMinColSize, csMinWidth.cx );
|
|
int iRight = 0;
|
|
for( int i = 0; i < m_pOutliner->m_iVisColumns; i++ )
|
|
{
|
|
if( i < m_iColHit )
|
|
{
|
|
iLeft += m_pOutliner->m_pColumn[i]->iCol;
|
|
}
|
|
else if( i > m_iColHit )
|
|
{
|
|
if( m_pOutliner->m_pColumn[i]->cType == ColumnVariable )
|
|
{
|
|
iRight += csMinWidth.cx; //max( m_pOutliner->m_pColumn[i]->iMinColSize, csMinWidth.cx );
|
|
}
|
|
else
|
|
{
|
|
iRight += m_pOutliner->m_pColumn[i]->iCol;
|
|
}
|
|
}
|
|
}
|
|
iRight = m_pOutliner->m_iTotalWidth - iRight;
|
|
if( iRight < iLeft )
|
|
{
|
|
iRight = iLeft;
|
|
}
|
|
RECT rcClip = { iLeft, 0, iRight, m_iHeaderHeight };
|
|
MapWindowPoints( CWnd::FromHandle( HWND_DESKTOP ), &rcClip );
|
|
|
|
#ifdef _WIN32
|
|
return ClipCursor( &rcClip );
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
BOOL COutlinerParent::TestCol( POINT &pt, int &iCol )
|
|
{
|
|
iCol = -1;
|
|
int i;
|
|
BOOL res = FALSE;
|
|
RECT rc, rcResize, rcClient;
|
|
|
|
m_bResizeArea = FALSE;
|
|
|
|
GetClientRect(&rcClient);
|
|
|
|
rc.top = rcResize.top = 0;
|
|
rc.bottom = rcResize.bottom = m_iHeaderHeight;
|
|
rc.left = 0;
|
|
rc.right = 0;
|
|
|
|
for ( i = 0; i < m_pOutliner->m_iVisColumns; i++ )
|
|
{
|
|
rc.left = rc.right;
|
|
rc.right = rc.left + m_pOutliner->m_pColumn[ i ]->iCol;
|
|
|
|
if (rc.right > (rcClient.right - m_iPusherWidth)) {
|
|
rc.right = rcClient.right - m_iPusherWidth;
|
|
}
|
|
|
|
if ( i < m_pOutliner->m_iVisColumns - 1 ) {
|
|
rcResize.left = rc.right - 4;
|
|
rcResize.right = rc.right + 4;
|
|
|
|
if ( ::PtInRect( &rcResize, pt ) ) {
|
|
m_bResizeArea = TRUE;
|
|
m_iColResize = i;
|
|
}
|
|
}
|
|
|
|
if ( ::PtInRect( &rc, pt ) ) {
|
|
m_rcTest = rc;
|
|
iCol = i;
|
|
res = TRUE;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void COutlinerParent::GetColumnRect( int iCol, RECT &rc )
|
|
{
|
|
GetClientRect(&rc);
|
|
if (m_bEnableFocusFrame)
|
|
{
|
|
rc.top = 1;
|
|
rc.left = 1;
|
|
rc.right = 1;
|
|
}
|
|
else
|
|
{
|
|
rc.left = 0;
|
|
rc.right = 0;
|
|
}
|
|
rc.bottom = m_iHeaderHeight;
|
|
if ( iCol >= 0 && iCol < m_pOutliner->m_iVisColumns ) {
|
|
for (int i = 0; i <= iCol; i++) {
|
|
rc.left = rc.right;
|
|
rc.right += m_pOutliner->m_pColumn[ i ]->iCol;
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutlinerParent::EnableHeaders(BOOL bEnable)
|
|
{
|
|
m_bDisableHeaders = !bEnable;
|
|
CRect rect;
|
|
GetClientRect(&rect);
|
|
Invalidate();
|
|
OnSize(0, rect.Width(), rect.Height());
|
|
}
|
|
|
|
void COutlinerParent::InvalidateColumn( int iCol )
|
|
{
|
|
RECT rc;
|
|
GetColumnRect( iCol, rc );
|
|
InvalidateRect( &rc );
|
|
}
|
|
|
|
void COutlinerParent::UpdateFocusFrame()
|
|
{
|
|
if (m_bEnableFocusFrame)
|
|
{
|
|
RECT clientRect;
|
|
GetClientRect(&clientRect);
|
|
InvalidateRect(&clientRect, FALSE);
|
|
::InflateRect(&clientRect, -1, -1);
|
|
clientRect.top = m_iHeaderHeight + 1;
|
|
ValidateRect(&clientRect);
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
BOOL COutlinerParent::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)
|
|
m_wndTip.RelayEvent(pMsg);
|
|
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
int COutlinerParent::OnCreate ( LPCREATESTRUCT lpCreateStruct )
|
|
{
|
|
int iRetVal = (int) Default();
|
|
|
|
if (m_pOutliner = GetOutliner ( ) ) {
|
|
CClientDC pdc ( this );
|
|
int m_rescsid = INTL_CharSetNameToID(INTL_ResourceCharSet());
|
|
LOGFONT lf;
|
|
memset(&lf,0,sizeof(LOGFONT));
|
|
lf.lfPitchAndFamily = FF_SWISS;
|
|
lf.lfCharSet = IntlGetLfCharset(m_rescsid); // Global lfCharSet
|
|
if (m_rescsid == CS_LATIN1)
|
|
strcpy(lf.lfFaceName, "MS Sans Serif");
|
|
else
|
|
strcpy(lf.lfFaceName, IntlGetUIPropFaceName(m_rescsid));
|
|
lf.lfHeight = -MulDiv(9,pdc.GetDeviceCaps(LOGPIXELSY), 72);
|
|
m_hToolFont = theApp.CreateAppFont( lf );
|
|
|
|
TEXTMETRIC tm;
|
|
HFONT hOldFont = (HFONT) pdc.SelectObject ( m_hToolFont );
|
|
pdc.GetTextMetrics ( &tm );
|
|
pdc.SelectObject ( hOldFont );
|
|
|
|
m_iHeaderHeight = tm.tmHeight + tm.tmExternalLeading + 4;
|
|
m_cxChar = tm.tmAveCharWidth;
|
|
|
|
LPCTSTR lpszClass = NULL;
|
|
m_pOutliner->CreateEx ( 0, lpszClass, NULL,
|
|
( m_bHasBorder ? WS_BORDER : 0 )|WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
|
|
0, 0, 0, 0, this->m_hWnd, lpCreateStruct->hMenu );
|
|
|
|
m_wndTip.Create(this);
|
|
m_wndTip.AddTool(this, IDS_SHOWHIDECOLUMNS, CRect(0,0,0,0), 1);
|
|
m_wndTip.Activate(TRUE);
|
|
} else {
|
|
iRetVal = -1;
|
|
}
|
|
m_iPusherWidth = GetSystemMetrics(SM_CXVSCROLL);
|
|
m_iPusherWidth = m_iPusherWidth > 20 ? m_iPusherWidth : 20;
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
void COutlinerParent::OnSize ( UINT nType, int cx, int cy )
|
|
{
|
|
if ( m_pOutliner )
|
|
{
|
|
m_pOutliner->m_iTotalWidth = cx - m_iPusherWidth;
|
|
if (m_bEnableFocusFrame)
|
|
{
|
|
m_pOutliner->MoveWindow ( 1,
|
|
m_bDisableHeaders ? 0 : m_iHeaderHeight,
|
|
cx - 2,
|
|
cy - ( m_bDisableHeaders ? 1 : m_iHeaderHeight + 1 ), TRUE );
|
|
}
|
|
else
|
|
{
|
|
m_pOutliner->MoveWindow ( 0,
|
|
m_bDisableHeaders ? 0 : m_iHeaderHeight,
|
|
cx,
|
|
cy - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ), TRUE );
|
|
}
|
|
m_wndTip.SetToolRect(this, 1, CRect(cx - m_iPusherWidth, 0, cx, m_iHeaderHeight));
|
|
}
|
|
}
|
|
|
|
void COutlinerParent::OnKeyDown ( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
if ( m_pOutliner )
|
|
m_pOutliner->OnKeyDown ( nChar, nRepCnt, nFlags );
|
|
else
|
|
Default();
|
|
}
|
|
|
|
void COutlinerParent::OnSetFocus ( CWnd * pOldWnd )
|
|
{
|
|
Default();
|
|
|
|
if ( m_pOutliner )
|
|
m_pOutliner->SetFocus ( );
|
|
}
|
|
|
|
void COutlinerParent::OnLButtonDown( UINT nFlags, CPoint point )
|
|
{
|
|
if ( m_pOutliner )
|
|
{
|
|
SetCapture ( );
|
|
m_ptHit = point;
|
|
|
|
if( m_bResizeArea )
|
|
{
|
|
m_bResizeColumn = TRUE;
|
|
|
|
ResizeClipCursor();
|
|
}
|
|
else
|
|
{
|
|
int iCol = 0;
|
|
if (TestCol( point, iCol )) {
|
|
m_rcDrag = m_rcHit = m_rcTest;
|
|
m_bHeaderSelected = TRUE;
|
|
m_iColHit = iCol;
|
|
m_idColHit = m_pOutliner->m_pColumn[ iCol ]->iCommand;
|
|
|
|
if ( m_pOutliner->m_pColumn[ iCol ]->bIsButton ) {
|
|
m_pOutliner->m_pColumn[ iCol ]->bDepressed = TRUE;
|
|
InvalidateColumn ( iCol );
|
|
}
|
|
}
|
|
int iTestPush = TestPusher(point);
|
|
if (iTestPush & m_iPusherState) {
|
|
m_iPusherHit = m_iPusherRgn = iTestPush;
|
|
InvalidatePusher();
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
}
|
|
Default();
|
|
}
|
|
|
|
void COutlinerParent::OnLButtonUp( UINT nFlags, CPoint point )
|
|
{
|
|
if ( GetCapture() != this )
|
|
return;
|
|
|
|
ReleaseCapture();
|
|
ClipCursor( NULL );
|
|
|
|
m_bHeaderSelected = FALSE;
|
|
|
|
if ( m_bResizeColumn )
|
|
{
|
|
m_bResizeColumn = FALSE;
|
|
m_bResizeArea = FALSE;
|
|
return;
|
|
}
|
|
|
|
if ( m_bDraggingHeader ) {
|
|
CDC *pDC = GetDC();
|
|
// pDC->DrawFocusRect(&m_rcDrag);
|
|
::BitBlt( pDC->m_hDC,
|
|
m_rcDrag.left,
|
|
m_rcDrag.top,
|
|
m_rcDrag.right - m_rcDrag.left,
|
|
m_rcDrag.bottom - m_rcDrag.top,
|
|
m_hdcDrag,
|
|
0,
|
|
0,
|
|
SRCINVERT );
|
|
VERIFY(::DeleteDC( m_hdcDrag ));
|
|
m_hdcDrag = NULL;
|
|
VERIFY(::DeleteObject( m_hbmDrag ));
|
|
m_hbmDrag = NULL;
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
if ( m_iColHit != -1 && m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed ) {
|
|
if ( !m_bDraggingHeader ) {
|
|
ColumnCommand ( m_pOutliner->m_pColumn[ m_iColHit ]->iCommand );
|
|
}
|
|
m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed = FALSE;
|
|
InvalidateColumn( m_iColHit );
|
|
}
|
|
|
|
m_bDraggingHeader = FALSE;
|
|
|
|
if ( m_iPusherHit ) {
|
|
m_iPusherRgn = TestPusher(point);
|
|
if ( m_iPusherRgn == m_iPusherHit) {
|
|
RECT rectClient;
|
|
GetClientRect(&rectClient);
|
|
switch (m_iPusherHit) {
|
|
case pusherLeft:
|
|
if ( m_iPusherState & pusherLeft ) {
|
|
m_pOutliner->m_iVisColumns++;
|
|
m_pOutliner->OnSize ( 0,
|
|
rectClient.right,
|
|
rectClient.bottom - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ) );
|
|
Invalidate();
|
|
m_pOutliner->Invalidate();
|
|
}
|
|
break;
|
|
case pusherRight:
|
|
if ( m_iPusherState & pusherRight ) {
|
|
m_pOutliner->m_iVisColumns--;
|
|
m_pOutliner->OnSize ( 0,
|
|
rectClient.right,
|
|
rectClient.bottom - ( m_bDisableHeaders ? 0 : m_iHeaderHeight ) );
|
|
Invalidate();
|
|
m_pOutliner->Invalidate();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
m_iPusherRgn = pusherNone;
|
|
m_iPusherHit = pusherNone;
|
|
}
|
|
}
|
|
|
|
BOOL COutlinerParent::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
|
|
{
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
ScreenToClient(&pt);
|
|
|
|
if (!CWnd::OnSetCursor( pWnd, nHitTest, message )) {
|
|
int iCol = -1;
|
|
if ( nHitTest == HTCLIENT &&
|
|
TestCol( pt, iCol) &&
|
|
m_bResizeArea &&
|
|
m_pOutliner->m_pColumn[ m_iColResize ]->cType == ColumnVariable ) {
|
|
iCol = m_iColResize;
|
|
for ( int i = iCol + 1; i < m_pOutliner->m_iVisColumns; i++ ) {
|
|
if ( m_pOutliner->m_pColumn[ i ]->cType == ColumnVariable ) {
|
|
SetCursor ( theApp.LoadCursor ( AFX_IDC_HSPLITBAR ) );
|
|
m_iColLoser = i;
|
|
m_iColHit = iCol;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
m_bResizeArea = FALSE;
|
|
|
|
SetCursor ( ::LoadCursor( NULL, IDC_ARROW ) );
|
|
|
|
return TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void COutlinerParent::OnMouseMove( UINT nFlags, CPoint point )
|
|
{
|
|
m_pt = point;
|
|
|
|
if (GetCapture() != this)
|
|
return;
|
|
|
|
int i;
|
|
|
|
if ( m_bResizeColumn ) {
|
|
int iDelta = point.x - m_ptHit.x;
|
|
|
|
m_ptHit = point;
|
|
|
|
m_pOutliner->SqueezeColumns( m_iColHit, iDelta );
|
|
for( i = m_iColHit; i < m_pOutliner->m_iVisColumns; i++ )
|
|
{
|
|
InvalidateColumn( i );
|
|
}
|
|
} else {
|
|
if ( m_bHeaderSelected ) {
|
|
if ( abs(point.x - m_ptHit.x) > 3 ) {
|
|
m_bDraggingHeader = TRUE;
|
|
m_bHeaderSelected = FALSE;
|
|
m_pOutliner->m_pColumn[ m_iColHit ]->bDepressed = FALSE;
|
|
InvalidateColumn( m_iColHit );
|
|
UpdateWindow();
|
|
|
|
// Create bitmap for dragging header
|
|
CDC *pDC = GetDC();
|
|
|
|
RECT rcBorder;
|
|
::SetRect( &rcBorder, 0, 0,
|
|
m_rcDrag.right - m_rcDrag.left, m_rcDrag.bottom - m_rcDrag.top );
|
|
m_hbmDrag = ::CreateBitmap( rcBorder.right, rcBorder.bottom, 1, 1, NULL );
|
|
m_hdcDrag = ::CreateCompatibleDC( pDC->m_hDC );
|
|
::SelectObject( m_hdcDrag, m_hbmDrag );
|
|
HFONT hOldFont = (HFONT) ::SelectObject ( m_hdcDrag, m_hToolFont );
|
|
::FillRect( m_hdcDrag, &rcBorder, (HBRUSH) GetStockObject( WHITE_BRUSH ) );
|
|
::FrameRect( m_hdcDrag, &rcBorder, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
|
|
::SetBkColor( m_hdcDrag, RGB(255, 255, 255) );
|
|
::SetTextColor( m_hdcDrag, RGB(0, 0, 0) );
|
|
|
|
DrawColumnHeader( m_hdcDrag, rcBorder, m_iColHit );
|
|
|
|
// Invert the sucker
|
|
::BitBlt( m_hdcDrag,
|
|
0, 0, rcBorder.right, rcBorder.bottom,
|
|
m_hdcDrag,
|
|
0, 0,
|
|
NOTSRCCOPY );
|
|
|
|
// Initially XOR the bitmap
|
|
::BitBlt( pDC->m_hDC,
|
|
m_rcDrag.left,
|
|
m_rcDrag.top,
|
|
m_rcDrag.right - m_rcDrag.left,
|
|
m_rcDrag.bottom - m_rcDrag.top,
|
|
m_hdcDrag,
|
|
0,
|
|
0,
|
|
SRCINVERT );
|
|
|
|
ReleaseDC(pDC);
|
|
}
|
|
}
|
|
|
|
if ( m_bDraggingHeader ) {
|
|
int iCol;
|
|
CDC *pDC = GetDC();
|
|
// Undo the last XOR
|
|
::BitBlt( pDC->m_hDC,
|
|
m_rcDrag.left,
|
|
m_rcDrag.top,
|
|
m_rcDrag.right - m_rcDrag.left,
|
|
m_rcDrag.bottom - m_rcDrag.top,
|
|
m_hdcDrag,
|
|
0,
|
|
0,
|
|
SRCINVERT );
|
|
POINT pt;
|
|
pt.x = point.x;
|
|
pt.y = 1; // ignore vertical movement
|
|
if ( TestCol( pt, iCol ) &&
|
|
(m_pOutliner->m_pColumn[ iCol ]->iCommand != m_idColHit) ) {
|
|
int iWidth = m_pOutliner->m_pColumn[ m_iColHit ]->iCol;
|
|
if ( ( iCol < m_iColHit && point.x - m_rcTest.left < iWidth ) ||
|
|
( iCol > m_iColHit && point.x > m_rcTest.right - iWidth ) ) {
|
|
|
|
// Shove everything down
|
|
|
|
OutlinerColumn_t *tmp;
|
|
tmp = m_pOutliner->m_pColumn[ m_iColHit ];
|
|
if (iCol < m_iColHit) {
|
|
for (i = m_iColHit; i > iCol; i--) {
|
|
m_pOutliner->m_pColumn[i] = m_pOutliner->m_pColumn[i - 1];
|
|
}
|
|
} else {
|
|
for (i = m_iColHit; i < iCol; i++) {
|
|
m_pOutliner->m_pColumn[i] = m_pOutliner->m_pColumn[i + 1];
|
|
}
|
|
}
|
|
m_pOutliner->m_pColumn[ iCol ] = tmp;
|
|
|
|
// Allow the Outliner a chance to respond to the fact that the columns
|
|
// have been adjusted. (Dave H.)
|
|
m_pOutliner->ColumnsSwapped();
|
|
|
|
// Redraw the relevent stuff
|
|
|
|
int iStart = m_iColHit < iCol ? m_iColHit : iCol;
|
|
int iEnd = m_iColHit < iCol ? iCol : m_iColHit;
|
|
|
|
for ( i = iStart; i <= iEnd; i++) {
|
|
m_pOutliner->InvalidateColumn ( i );
|
|
InvalidateColumn ( i );
|
|
}
|
|
|
|
m_pOutliner->UpdateWindow();
|
|
UpdateWindow();
|
|
m_iColHit = iCol;
|
|
}
|
|
}
|
|
m_rcDrag.left = point.x + (m_rcHit.left - m_ptHit.x);
|
|
m_rcDrag.right = point.x + (m_rcHit.right - m_ptHit.x);
|
|
|
|
// XOR the header bitmap
|
|
::BitBlt( pDC->m_hDC,
|
|
m_rcDrag.left,
|
|
m_rcDrag.top,
|
|
m_rcDrag.right - m_rcDrag.left,
|
|
m_rcDrag.bottom - m_rcDrag.top,
|
|
m_hdcDrag,
|
|
0,
|
|
0,
|
|
SRCINVERT );
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
if ( m_iPusherHit ) {
|
|
int iTestPush;
|
|
if ( (iTestPush = TestPusher( point )) != m_iPusherRgn ) {
|
|
m_iPusherRgn = iTestPush;
|
|
InvalidatePusher();
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
}
|
|
Default();
|
|
}
|
|
|
|
void COutlinerParent::DrawButtonRect( HDC hDC, const RECT &rect, BOOL bDepressed )
|
|
{
|
|
HPEN hBlackPen = (HPEN) ::GetStockObject(BLACK_PEN);
|
|
HPEN hShadowPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_BTNSHADOW ) );
|
|
HPEN hHighLightPen = ::CreatePen( PS_SOLID, 0, GetSysColor ( COLOR_BTNHIGHLIGHT ) );
|
|
HPEN hLightPen = NULL;
|
|
#ifdef _WIN32
|
|
if ( sysInfo.m_bWin4 ) {
|
|
hLightPen = ::CreatePen( PS_SOLID, 0, GetSysColor( COLOR_3DLIGHT ) );
|
|
}
|
|
#endif
|
|
|
|
HPEN hOldPen = (HPEN) ::SelectObject ( hDC, bDepressed ? hShadowPen : hBlackPen );
|
|
::MoveToEx( hDC, rect.left, rect.bottom - 1, NULL );
|
|
::LineTo( hDC, rect.right - 1, rect.bottom - 1 );
|
|
::LineTo( hDC, rect.right - 1, rect.top - 1 );
|
|
|
|
if ( !bDepressed )
|
|
{
|
|
::SelectObject( hDC, hShadowPen );
|
|
::MoveToEx( hDC, rect.left + 1, rect.bottom - 2, NULL );
|
|
::LineTo( hDC, rect.right - 2, rect.bottom - 2 );
|
|
::LineTo( hDC, rect.right - 2, rect.top );
|
|
|
|
if ( hLightPen ) {
|
|
::SelectObject( hDC, hLightPen );
|
|
} else {
|
|
::SelectObject( hDC, hHighLightPen );
|
|
}
|
|
::MoveToEx( hDC, rect.left + 1, rect.bottom - 3, NULL );
|
|
::LineTo( hDC, rect.left + 1, rect.top + 1 );
|
|
::LineTo( hDC, rect.right - 2, rect.top + 1 );
|
|
}
|
|
|
|
::SelectObject( hDC, bDepressed ? hShadowPen : hHighLightPen );
|
|
::MoveToEx( hDC, rect.left, rect.bottom - 2, NULL );
|
|
::LineTo( hDC, rect.left, rect.top );
|
|
::LineTo( hDC, rect.right - 1, rect.top );
|
|
|
|
::SelectObject( hDC, hOldPen );
|
|
|
|
VERIFY( ::DeleteObject( hShadowPen ));
|
|
VERIFY( ::DeleteObject( hHighLightPen ));
|
|
if ( hLightPen )
|
|
VERIFY( ::DeleteObject( hLightPen ));
|
|
}
|
|
|
|
void COutlinerParent::DrawColumnHeader( HDC hdc, const RECT &rect, int iCol )
|
|
{
|
|
CRect rcText = rect;
|
|
BOOL bDep = m_pOutliner->m_pColumn[ iCol ]->bDepressed &&
|
|
m_pOutliner->m_pColumn[ iCol ]->bIsButton;
|
|
|
|
if ( bDep ) {
|
|
::OffsetRect(&rcText, 1, 1);
|
|
}
|
|
|
|
if (!RenderData( m_pOutliner->m_pColumn[ iCol ]->iCommand, rcText, *(CDC::FromHandle(hdc)),
|
|
m_pOutliner->m_pColumn[ iCol ]->pHeader )) {
|
|
::InflateRect(&rcText, -4, 0);
|
|
|
|
UINT dwDTFormat = DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER;
|
|
|
|
switch ( m_pOutliner->m_pColumn[ iCol ]->alignment ) {
|
|
case AlignCenter:
|
|
dwDTFormat |= DT_CENTER;
|
|
break;
|
|
case AlignRight:
|
|
dwDTFormat |= DT_RIGHT;
|
|
break;
|
|
case AlignLeft:
|
|
dwDTFormat |= DT_LEFT;
|
|
}
|
|
|
|
WFE_DrawTextEx( 0, hdc,
|
|
(LPTSTR) m_pOutliner->m_pColumn[ iCol ]->pHeader, -1,
|
|
&rcText, dwDTFormat, WFE_DT_CROPRIGHT );
|
|
}
|
|
}
|
|
void COutlinerParent::OnPaint ( )
|
|
{
|
|
CPaintDC pdc ( this );
|
|
|
|
if ( !m_pOutliner || m_bDisableHeaders )
|
|
return;
|
|
|
|
int i, offset;
|
|
|
|
// we might use these in the for() loop below --- make sure
|
|
// they stay in scope since we don't restore into the CDC until
|
|
// the end of the routine
|
|
HFONT hOldFont = (HFONT) pdc.SelectObject ( m_hToolFont );
|
|
COLORREF cOldText = pdc.SetTextColor(GetSysColor(COLOR_BTNTEXT));
|
|
COLORREF cOldBk = pdc.SetBkColor(GetSysColor(COLOR_BTNFACE));
|
|
|
|
CRect rectClient;
|
|
GetClientRect ( &rectClient );
|
|
int iMaxHeaderWidth = rectClient.right - m_iPusherWidth;
|
|
|
|
for ( i = offset = 0; (i < m_pOutliner->m_iVisColumns) && (offset < iMaxHeaderWidth); i++ )
|
|
{
|
|
BOOL bDep = m_pOutliner->m_pColumn[ i ]->bDepressed &&
|
|
m_pOutliner->m_pColumn[ i ]->bIsButton;
|
|
CRect rect( offset, 0, m_pOutliner->m_pColumn[ i ]->iCol + offset, m_iHeaderHeight );
|
|
|
|
if (rect.right > iMaxHeaderWidth ) {
|
|
rect.right = iMaxHeaderWidth;
|
|
}
|
|
|
|
RECT rcInter;
|
|
if ( ::IntersectRect ( &rcInter, &pdc.m_ps.rcPaint, &rect ) )
|
|
{
|
|
RECT rcText = rect;
|
|
::InflateRect(&rcText,-2,-2);
|
|
::FillRect(pdc.m_hDC, &rcText, sysInfo.m_hbrBtnFace );
|
|
DrawColumnHeader( pdc.m_hDC, rcText, i );
|
|
DrawButtonRect( pdc.m_hDC, rect, bDep );
|
|
}
|
|
|
|
offset += m_pOutliner->m_pColumn[ i ]->iCol;
|
|
}
|
|
|
|
// Fill in the gap on the right
|
|
|
|
if (offset < iMaxHeaderWidth) {
|
|
RECT rect = {offset, 0, iMaxHeaderWidth, m_iHeaderHeight};
|
|
RECT rcInter;
|
|
|
|
if ( IntersectRect( &rcInter, &pdc.m_ps.rcPaint, &rect ) ) {
|
|
RECT rcText = rect;
|
|
::InflateRect(&rcText,-2,-2);
|
|
::FillRect(pdc.m_hDC, &rcText, sysInfo.m_hbrBtnFace );
|
|
DrawButtonRect( pdc.m_hDC, rect, FALSE );
|
|
}
|
|
}
|
|
|
|
CRect rect(rectClient.right - m_iPusherWidth, 0, rectClient.right, m_iHeaderHeight );
|
|
CRect iRect;
|
|
|
|
if ( iRect.IntersectRect ( &pdc.m_ps.rcPaint, &rect ) ) {
|
|
int idxImage;
|
|
::FillRect ( pdc.m_hDC, &rect, sysInfo.m_hbrBtnFace );
|
|
|
|
m_iPusherState = pusherNone;
|
|
if ( m_pOutliner->m_iNumColumns > 1 ) {
|
|
if (m_pOutliner->m_iVisColumns > 1) {
|
|
m_iPusherState |= pusherRight;
|
|
}
|
|
if (m_pOutliner->m_iVisColumns < m_pOutliner->m_iNumColumns) {
|
|
m_iPusherState |= pusherLeft;
|
|
}
|
|
}
|
|
|
|
POINT ptBitmap;
|
|
RECT rect2 = rect;
|
|
|
|
// Draw left pusher
|
|
rect2.right = (rect.left + rect.right + 1) / 2;
|
|
|
|
ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4;
|
|
ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4;
|
|
if ( m_iPusherRgn == pusherLeft ) {
|
|
ptBitmap.x++;
|
|
ptBitmap.y++;
|
|
}
|
|
idxImage = m_iPusherState & pusherLeft ?
|
|
IDX_PUSHLEFT : IDX_PUSHLEFTI;
|
|
m_pIImage->DrawImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc, TRUE);
|
|
DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherLeft );
|
|
|
|
// Draw right pusher
|
|
rect2.left = rect2.right;
|
|
rect2.right = rect.right;
|
|
ptBitmap.x = (rect2.left + rect2.right + 1) / 2 - 4;
|
|
ptBitmap.y = (rect2.top + rect2.bottom + 1) / 2 - 4;
|
|
if ( m_iPusherRgn == pusherRight ) {
|
|
ptBitmap.x++;
|
|
ptBitmap.y++;
|
|
}
|
|
idxImage = m_iPusherState & pusherRight ?
|
|
IDX_PUSHRIGHT : IDX_PUSHRIGHTI;
|
|
m_pIImage->DrawImage( idxImage, ptBitmap.x, ptBitmap.y, &pdc, TRUE);
|
|
DrawButtonRect( pdc.m_hDC, rect2, m_iPusherRgn == pusherRight );
|
|
}
|
|
|
|
pdc.SelectObject ( hOldFont );
|
|
pdc.SetTextColor ( cOldText );
|
|
pdc.SetBkColor ( cOldBk );
|
|
|
|
if (m_bEnableFocusFrame)
|
|
{
|
|
HBRUSH hBrush = NULL;
|
|
if (GetFocus() == m_pOutliner)
|
|
hBrush = ::CreateSolidBrush( RGB(0, 0, 0) );
|
|
else
|
|
hBrush = ::CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
|
|
|
|
RECT clientRect;
|
|
GetClientRect(&clientRect);
|
|
::FrameRect( pdc.m_hDC, &clientRect, hBrush );
|
|
VERIFY(DeleteObject( hBrush ));
|
|
}
|
|
|
|
}
|
|
|
|
BOOL COutlinerParent::OnEraseBkgnd( CDC * )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// Overloadable methods
|
|
|
|
BOOL COutlinerParent::ColumnCommand(int idCol)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COutlinerParent::RenderData(int idColumn, CRect & rect, CDC & dc, LPCTSTR lpsz )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COutlinerView
|
|
|
|
BEGIN_MESSAGE_MAP(COutlinerView,CView)
|
|
ON_WM_CREATE()
|
|
ON_WM_SIZE()
|
|
ON_WM_SETFOCUS()
|
|
END_MESSAGE_MAP()
|
|
|
|
BOOL COutlinerView::PreCreateWindow(CREATESTRUCT& cs)
|
|
{
|
|
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
|
|
return CView::PreCreateWindow(cs);
|
|
}
|
|
|
|
void COutlinerView::OnDraw ( CDC * pDC )
|
|
{
|
|
}
|
|
|
|
int COutlinerView::OnCreate ( LPCREATESTRUCT lpCreateStruct )
|
|
{
|
|
int iRetVal = CView::OnCreate ( lpCreateStruct );
|
|
LPCTSTR lpszClass = AfxRegisterWndClass( CS_VREDRAW, ::LoadCursor(NULL, IDC_ARROW));
|
|
m_pOutlinerParent->Create( lpszClass, _T("NSOutlinerParent"),
|
|
WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN,
|
|
CRect(0,0,0,0), this, 101 );
|
|
return iRetVal;
|
|
}
|
|
|
|
void COutlinerView::OnSize ( UINT nType, int cx, int cy )
|
|
{
|
|
CView::OnSize ( nType, cx, cy );
|
|
m_pOutlinerParent->MoveWindow ( 0, 0, cx, cy, TRUE );
|
|
}
|
|
|
|
void COutlinerView::OnSetFocus ( CWnd * pOldWnd )
|
|
{
|
|
CView::OnSetFocus ( pOldWnd );
|
|
m_pOutlinerParent->SetFocus ( );
|
|
}
|
|
|
|
|