465 lines
10 KiB
C++
465 lines
10 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// splitex.cpp
|
|
// Based upon code from Oleg G. Galkin
|
|
// Modified to handle multiple hidden rows
|
|
|
|
#include "stdafx.h"
|
|
#include "splitex.h"
|
|
|
|
#if defined(_DEBUG) && !defined(MMGR)
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSplitterWndEx
|
|
|
|
CSplitterWndEx::CSplitterWndEx()
|
|
{
|
|
m_arr = 0;
|
|
m_length = 0;
|
|
}
|
|
|
|
CSplitterWndEx::~CSplitterWndEx()
|
|
{
|
|
delete [] m_arr;
|
|
}
|
|
|
|
int CSplitterWndEx::Id_short(int row, int col)
|
|
{
|
|
return AFX_IDW_PANE_FIRST + row * 16 + col;
|
|
}
|
|
|
|
void CSplitterWndEx::ShowRow(int r)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_nRows < m_nMaxRows);
|
|
|
|
ASSERT(m_arr);
|
|
ASSERT(r < m_length);
|
|
ASSERT(m_arr[r] >= m_nRows);
|
|
ASSERT(m_arr[r] < m_length);
|
|
|
|
int rowNew = r;
|
|
int cyNew = m_pRowInfo[m_arr[r]].nCurSize;
|
|
int cyIdealNew = m_pRowInfo[m_arr[r]].nIdealSize;
|
|
|
|
int new_val = 0;
|
|
|
|
for (int i = rowNew - 1; i >= 0; i--)
|
|
if (m_arr[i] < m_nRows) // not hidden
|
|
{
|
|
new_val = m_arr[i] + 1;
|
|
break;
|
|
}
|
|
|
|
int old_val = m_arr[rowNew];
|
|
|
|
m_nRows++; // add a row
|
|
|
|
// fill the hided row
|
|
int row;
|
|
for (int col = 0; col < m_nCols; col++)
|
|
{
|
|
CWnd* pPaneShow = GetDlgItem(
|
|
Id_short(old_val, col));
|
|
ASSERT(pPaneShow != NULL);
|
|
pPaneShow->ShowWindow(SW_SHOWNA);
|
|
|
|
for (row = m_length - 1; row >= 0; row--)
|
|
{
|
|
if ((m_arr[row] >= new_val) &&
|
|
(m_arr[row] < old_val))
|
|
{
|
|
CWnd* pPane = CSplitterWnd::GetPane(m_arr[row], col);
|
|
ASSERT(pPane != NULL);
|
|
pPane->SetDlgCtrlID(Id_short(m_arr[row] + 1, col));
|
|
}
|
|
}
|
|
pPaneShow->SetDlgCtrlID(Id_short(new_val, col));
|
|
}
|
|
|
|
for (row = 0; row < m_length; row++)
|
|
if ((m_arr[row] >= new_val) &&
|
|
(m_arr[row] < old_val))
|
|
m_arr[row]++;
|
|
|
|
m_arr[rowNew] = new_val;
|
|
|
|
//new panes have been created -- recalculate layout
|
|
for (row = new_val + 1; row < m_length; row++)
|
|
{
|
|
if (m_arr[row]<m_nRows)
|
|
{
|
|
m_pRowInfo[m_arr[row]].nIdealSize = m_pRowInfo[m_arr[row-1]].nCurSize;
|
|
m_pRowInfo[m_arr[row]].nCurSize = m_pRowInfo[m_arr[row-1]].nCurSize;
|
|
}
|
|
}
|
|
if (cyNew>=0x10000)
|
|
{
|
|
int rowToResize=(cyNew>>16)-1;
|
|
cyNew%=0x10000;
|
|
cyIdealNew%=0x10000;
|
|
m_pRowInfo[m_arr[rowToResize]].nCurSize-=cyNew+m_cxSplitter;
|
|
m_pRowInfo[m_arr[rowToResize]].nIdealSize=m_pRowInfo[m_arr[rowToResize]].nCurSize;//-=cyIdealNew+m_cxSplitter;
|
|
}
|
|
|
|
m_pRowInfo[new_val].nIdealSize = cyNew;
|
|
m_pRowInfo[new_val].nCurSize = cyNew;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CSplitterWndEx::ShowColumn(int c)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_nCols < m_nMaxCols);
|
|
|
|
ASSERT(m_arr);
|
|
ASSERT(c < m_length);
|
|
ASSERT(m_arr[c] >= m_nRows);
|
|
ASSERT(m_arr[c] < m_length);
|
|
|
|
int colNew = c;
|
|
int cxNew = m_pColInfo[m_arr[c]].nCurSize;
|
|
int cxIdealNew = m_pColInfo[m_arr[c]].nIdealSize;
|
|
|
|
int new_val = 0;
|
|
|
|
for (int i = colNew - 1; i >= 0; i--)
|
|
if (m_arr[i] < m_nCols) // not hidden
|
|
{
|
|
new_val = m_arr[i] + 1;
|
|
break;
|
|
}
|
|
|
|
int old_val = m_arr[colNew];
|
|
|
|
m_nCols++; // add a col
|
|
|
|
// fill the hided col
|
|
int col;
|
|
for (int row = 0; row < m_nRows; row++)
|
|
{
|
|
CWnd* pPaneShow = GetDlgItem(
|
|
Id_short(row, old_val));
|
|
ASSERT(pPaneShow != NULL);
|
|
pPaneShow->ShowWindow(SW_SHOWNA);
|
|
|
|
for (col = m_length - 1; col >= 0; col--)
|
|
{
|
|
if ((m_arr[col] >= new_val) &&
|
|
(m_arr[col] < old_val))
|
|
{
|
|
CWnd* pPane = CSplitterWnd::GetPane(row, m_arr[col]);
|
|
ASSERT(pPane != NULL);
|
|
pPane->SetDlgCtrlID(Id_short(row, m_arr[col]+1));
|
|
}
|
|
}
|
|
pPaneShow->SetDlgCtrlID(Id_short(row, new_val));
|
|
}
|
|
|
|
for (col = 0; col < m_length; col++)
|
|
if ((m_arr[col] >= new_val) &&
|
|
(m_arr[col] < old_val))
|
|
m_arr[col]++;
|
|
|
|
m_arr[colNew] = new_val;
|
|
|
|
//new panes have been created -- recalculate layout
|
|
for (col = new_val + 1; col < m_length; col++)
|
|
{
|
|
if (m_arr[col]<m_nCols)
|
|
{
|
|
m_pColInfo[m_arr[col]].nIdealSize = m_pColInfo[m_arr[col-1]].nCurSize;
|
|
m_pColInfo[m_arr[col]].nCurSize = m_pColInfo[m_arr[col-1]].nCurSize;
|
|
}
|
|
}
|
|
if (cxNew>=0x10000)
|
|
{
|
|
int colToResize=(cxNew>>16)-1;
|
|
cxNew%=0x10000;
|
|
cxIdealNew%=0x10000;
|
|
m_pColInfo[m_arr[colToResize]].nCurSize-=cxNew+m_cySplitter;
|
|
m_pColInfo[m_arr[colToResize]].nIdealSize=m_pColInfo[m_arr[colToResize]].nCurSize;//-=cxIdealNew+m_cySplitter;
|
|
}
|
|
|
|
m_pColInfo[new_val].nIdealSize = cxNew;
|
|
m_pColInfo[new_val].nCurSize = cxNew;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CSplitterWndEx::HideRow(int rowHide,int rowToResize)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_nRows > 1);
|
|
|
|
if (m_arr)
|
|
ASSERT(m_arr[rowHide] < m_nRows);
|
|
|
|
// if the row has an active window -- change it
|
|
int rowActive, colActive;
|
|
|
|
if (!m_arr)
|
|
{
|
|
m_arr = new int[m_nRows];
|
|
for (int i = 0; i < m_nRows; i++)
|
|
m_arr[i] = i;
|
|
m_length = m_nRows;
|
|
}
|
|
|
|
if (GetActivePane(&rowActive, &colActive) != NULL &&
|
|
rowActive == rowHide) //colActive == rowHide)
|
|
{
|
|
if (++rowActive >= m_nRows)
|
|
rowActive = 0;
|
|
//SetActivePane(rowActive, colActive);
|
|
|
|
SetActivePane(rowActive, colActive);
|
|
}
|
|
|
|
// hide all row panes
|
|
for (int col = 0; col < m_nCols; col++)
|
|
{
|
|
CWnd* pPaneHide = CSplitterWnd::GetPane(m_arr[rowHide], col);
|
|
ASSERT(pPaneHide != NULL);
|
|
pPaneHide->ShowWindow(SW_HIDE);
|
|
|
|
for (int row = rowHide + 1; row < m_length; row++)
|
|
{
|
|
if (m_arr[row] < m_nRows )
|
|
{
|
|
CWnd* pPane = CSplitterWnd::GetPane(m_arr[row], col);
|
|
ASSERT(pPane != NULL);
|
|
pPane->SetDlgCtrlID(Id_short(row-1, col));
|
|
m_arr[row]--;
|
|
}
|
|
}
|
|
pPaneHide->SetDlgCtrlID(
|
|
Id_short(m_nRows -1 , col));
|
|
}
|
|
|
|
int oldsize=m_pRowInfo[m_arr[rowHide]].nCurSize;
|
|
for (int row=rowHide;row<(m_length-1);row++)
|
|
{
|
|
if (m_arr[row+1] < m_nRows )
|
|
{
|
|
m_pRowInfo[m_arr[row]].nCurSize=m_pRowInfo[m_arr[row+1]].nCurSize;
|
|
m_pRowInfo[m_arr[row]].nIdealSize=m_pRowInfo[m_arr[row+1]].nCurSize;
|
|
}
|
|
}
|
|
if (rowToResize!=-1)
|
|
{
|
|
m_pRowInfo[m_arr[rowToResize]].nCurSize+=oldsize+m_cySplitter;
|
|
m_pRowInfo[m_arr[rowToResize]].nIdealSize+=oldsize+m_cySplitter;
|
|
oldsize+=0x10000*(rowToResize+1);
|
|
}
|
|
|
|
m_pRowInfo[m_nRows - 1].nCurSize =oldsize;
|
|
m_pRowInfo[m_nRows - 1].nIdealSize =oldsize;
|
|
|
|
m_arr[rowHide] = m_nRows-1;
|
|
|
|
|
|
m_nRows--;
|
|
RecalcLayout();
|
|
}
|
|
|
|
void CSplitterWndEx::HideColumn(int colHide, int colToResize)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_nCols > 1);
|
|
|
|
if (m_arr)
|
|
ASSERT(m_arr[colHide] < m_nCols);
|
|
|
|
// if the col has an active window -- change it
|
|
int colActive, rowActive;
|
|
|
|
if (!m_arr)
|
|
{
|
|
m_arr = new int[m_nCols];
|
|
for (int i = 0; i < m_nCols; i++)
|
|
m_arr[i] = i;
|
|
m_length = m_nCols;
|
|
}
|
|
|
|
if (GetActivePane(&rowActive, &colActive) != NULL &&
|
|
colActive == colHide)
|
|
{
|
|
if (++colActive >= m_nCols)
|
|
colActive = 0;
|
|
SetActivePane(rowActive, colActive);
|
|
}
|
|
|
|
// hide all row panes
|
|
for (int row = 0; row < m_nRows; row++)
|
|
{
|
|
CWnd* pPaneHide = CSplitterWnd::GetPane(row, m_arr[colHide]);
|
|
ASSERT(pPaneHide != NULL);
|
|
pPaneHide->ShowWindow(SW_HIDE);
|
|
|
|
for (int col = colHide + 1; col < m_length; col++)
|
|
{
|
|
if (m_arr[col] < m_nCols )
|
|
{
|
|
CWnd* pPane = CSplitterWnd::GetPane(row, m_arr[col]);
|
|
ASSERT(pPane != NULL);
|
|
pPane->SetDlgCtrlID(Id_short(row, col-1));
|
|
m_arr[col]--;
|
|
}
|
|
}
|
|
pPaneHide->SetDlgCtrlID(
|
|
Id_short(row, m_nCols -1));
|
|
}
|
|
|
|
int oldsize = m_pColInfo[m_arr[colHide]].nCurSize;
|
|
for (int col = colHide; col < (m_length - 1); ++col)
|
|
{
|
|
if (m_arr[col + 1] < m_nCols)
|
|
{
|
|
m_pColInfo[m_arr[col]].nCurSize = m_pColInfo[m_arr[col + 1]].nCurSize;
|
|
m_pColInfo[m_arr[col]].nIdealSize = m_pColInfo[m_arr[col + 1]].nCurSize;
|
|
}
|
|
}
|
|
if (colToResize != -1)
|
|
{
|
|
m_pColInfo[m_arr[colToResize]].nCurSize += oldsize + m_cxSplitter;
|
|
m_pColInfo[m_arr[colToResize]].nIdealSize += oldsize + m_cxSplitter;
|
|
oldsize += 0x10000 * (colToResize + 1);
|
|
}
|
|
|
|
m_pColInfo[m_nCols - 1].nCurSize = oldsize;
|
|
m_pColInfo[m_nCols - 1].nIdealSize = oldsize;
|
|
|
|
m_arr[colHide] = m_nCols - 1;
|
|
|
|
m_nCols--;
|
|
RecalcLayout();
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CSplitterWndEx, CSplitterWnd)
|
|
//{{AFX_MSG_MAP(CSplitterWndEx)
|
|
// NOTE - the ClassWizard will add and remove mapping macros here.
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
CWnd* CSplitterWndEx::GetPane(int row, int col)
|
|
{
|
|
if (!m_arr)
|
|
return CSplitterWnd::GetPane(row,col);
|
|
else
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
CWnd* pView = GetDlgItem(IdFromRowCol(m_arr[row], col));
|
|
ASSERT(pView != NULL); // panes can be a CWnd, but are usually CViews
|
|
return pView;
|
|
}
|
|
}
|
|
|
|
int CSplitterWndEx::IdFromRowCol(int row, int col) const
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(row >= 0);
|
|
ASSERT(row < (m_arr?m_length:m_nRows));
|
|
ASSERT(col >= 0);
|
|
ASSERT(col < m_nCols);
|
|
|
|
return AFX_IDW_PANE_FIRST + row * 16 + col;
|
|
}
|
|
|
|
BOOL CSplitterWndEx::IsChildPane(CWnd* pWnd, int* pRow, int* pCol)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pWnd);
|
|
|
|
UINT nID = ::GetDlgCtrlID(pWnd->m_hWnd);
|
|
if (IsChild(pWnd) && nID >= AFX_IDW_PANE_FIRST && nID <= AFX_IDW_PANE_LAST)
|
|
{
|
|
if (pWnd->GetParent()!=this)
|
|
return FALSE;
|
|
if (pRow != NULL)
|
|
*pRow = (nID - AFX_IDW_PANE_FIRST) / 16;
|
|
if (pCol != NULL)
|
|
*pCol = (nID - AFX_IDW_PANE_FIRST) % 16;
|
|
ASSERT(pRow == NULL || *pRow < (m_arr?m_length:m_nRows));
|
|
ASSERT(pCol == NULL || *pCol < m_nCols);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (pRow != NULL)
|
|
*pRow = -1;
|
|
if (pCol != NULL)
|
|
*pCol = -1;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CWnd* CSplitterWndEx::GetActivePane(int* pRow, int* pCol)
|
|
// return active view, NULL when no active view
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// attempt to use active view of frame window
|
|
CWnd* pView = NULL;
|
|
CFrameWnd* pFrameWnd = GetParentFrame();
|
|
ASSERT_VALID(pFrameWnd);
|
|
pView = pFrameWnd->GetActiveView();
|
|
|
|
// failing that, use the current focus
|
|
if (pView == NULL)
|
|
pView = GetFocus();
|
|
|
|
// make sure the pane is a child pane of the splitter
|
|
if (pView != NULL && !IsChildPane(pView, pRow, pCol))
|
|
pView = NULL;
|
|
|
|
return pView;
|
|
}
|
|
|
|
BOOL CSplitterWndEx::IsRowHidden(int row)
|
|
{
|
|
return m_arr[row]>=m_nRows;
|
|
|
|
}
|
|
|
|
void CSplitterWndEx::GetRowInfoEx(int row, int &cyCur, int &cyMin)
|
|
{
|
|
if (!m_arr)
|
|
GetRowInfo(row,cyCur,cyMin);
|
|
else
|
|
{
|
|
if (m_pRowInfo[m_arr[row]].nCurSize>0x10000)
|
|
cyCur=m_pRowInfo[m_arr[row]].nCurSize/0x10000;
|
|
else
|
|
cyCur=m_pRowInfo[m_arr[row]].nCurSize%0x10000;
|
|
cyMin=0;
|
|
}
|
|
}
|
|
|
|
__int64 CSplitterWndEx::GetSizes() const
|
|
{
|
|
LARGE_INTEGER v;
|
|
int dummy;
|
|
int s1, s2;
|
|
if (BarIsHorizontal())
|
|
{
|
|
GetRowInfo(0, s1, dummy);
|
|
GetRowInfo(1, s2, dummy);
|
|
v.HighPart = s1;
|
|
v.LowPart = s2;
|
|
}
|
|
else
|
|
{
|
|
GetColumnInfo(0, s1, dummy);
|
|
GetColumnInfo(1, s2, dummy);
|
|
v.HighPart = s1;
|
|
v.LowPart = s2;
|
|
}
|
|
return v.QuadPart;
|
|
}
|