2020-09-30 17:12:29 +02:00

597 lines
13 KiB
C++

// Implementation for class CTMMultipleSelect
// -- A Multiple Selection Text List
// Created 5 October 1992 by Ronald C. Murray
#include "stdafx.h"
#include "Indicate.h"
#include "TMMulti.h"
CTMMultipleSelect::CTMMultipleSelect()
{
m_rowFocus = 0;
m_hlType = CHighlight::DOT_BOX_TEXT;
m_fHLOn = FALSE;
m_fMouseButtonDown = FALSE;
m_usMethod = CIndicatorSet::SET_BIT;
m_iRowStart = 0;
m_iRowLast = 0;
m_fShiftDown = FALSE;
m_ptm = NULL;
m_pisSelection = NULL;
}
CTMMultipleSelect *CTMMultipleSelect::NewTMMultipleSelect(CTextMatrix *ptm, long rowStart,
UINT hlType, BOOL fHighlightOn
)
{
CTMMultipleSelect *ptmms= NULL;
__try
{
ptmms= New CTMMultipleSelect();
ptmms->Initial(ptm, rowStart, hlType, fHighlightOn);
}
__finally
{
if (_abnormal_termination() && ptmms)
{
delete ptmms; ptmms= NULL;
}
}
return ptmms;
}
void CTMMultipleSelect::Initial(CTextMatrix *ptm, long rowStart,
UINT hlType, BOOL fHighlightOn
)
{
m_rowFocus = rowStart;
m_hlType = hlType;
m_fHLOn = fHighlightOn;
ASSERT(ptm);
m_ptm = ptm; // Note: Don't use AttachRef here.
// It'll create a reference loop!
AttachRef(m_pisSelection, CIndicatorSet::NewIndicatorSet(m_ptm->UnfilteredRowCount()));
// if (m_fHLOn && m_hlType == CHighlight::HIGHLIGHT_TEXT)
// SetRowSelection(m_rowFocus, TRUE);
}
long CTMMultipleSelect::GetHighlights(long rowTop, long colLeft,
long cRows, long cCols,
long cHighlights, CHighlight *phl
)
{
long iLowRow, iLimitRow;
if ((m_fMouseButtonDown || m_fShiftDown) && m_iRowStart != m_iRowLast)
{
if (m_iRowStart > m_iRowLast)
{
iLowRow = m_iRowLast ;
iLimitRow = m_iRowStart;
}
else
{
iLowRow = m_iRowStart+1;
iLimitRow = m_iRowLast +1;
}
if (iLowRow < rowTop) iLowRow= rowTop;
if (iLimitRow > rowTop+cRows) iLimitRow= rowTop+cRows;
}
else iLowRow= iLimitRow= m_ptm->RowCount();
int cIndices;
int aiLines[MAX_SCREEN_LINES];
cIndices= m_ptm->Data_Indices(rowTop, (int *) aiLines, cRows);
BOOL fCountOnly= !phl;
int *pliRow= aiLines;
long chlResidual= 0;
int cbWidth= m_ptm->ColCount();
for ( ; cRows && cIndices; cRows--, cIndices--, rowTop++, pliRow++)
{
BOOL fHighlighted= FALSE;
BOOL fSettingBits= (m_usMethod == CIndicatorSet::SET_BIT);
if (rowTop >= iLowRow && rowTop <iLimitRow)
fHighlighted= fSettingBits;
else fHighlighted= m_pisSelection->IsBitSet(*pliRow);
if (fHighlighted)
{
if (fCountOnly)
{
++chlResidual;
continue;
}
if (cHighlights)
{
phl->m_row = rowTop;
phl->m_col = 0;
phl->m_cChars = cbWidth;
phl->m_iType = CHighlight::HIGHLIGHT_TEXT;
-- cHighlights;
++ phl;
}
else ++chlResidual;
}
}
#if 0
BOOL fShowStart= FALSE, fShowLast= FALSE;
if (m_iRowStart != m_iRowLast)
{
if (fCountOnly) ++chlResidual;
else
{
phl->m_row = m_iRowStart;
phl->m_col = 0;
phl->m_cChars = cbWidth;
phl->m_iType = CHighlight::DASH_BOX_TEXT;
-- cHighlights;
++ phl;
fShowStart= TRUE;
}
}
if (fCountOnly) ++chlResidual;
else
{
phl->m_row = m_iRowLast;
phl->m_col = 0;
phl->m_cChars = cbWidth;
phl->m_iType = CHighlight::DOT_BOX_TEXT;
-- cHighlights;
++ phl;
fShowLast= TRUE;
}
if (fShowStart && fShowLast && m_iRowStart > m_iRowLast)
{
CHighlight hl= *(phl-2);
*(phl-2)= *(phl-1);
*(phl-1)= hl;
}
#endif
return fCountOnly? chlResidual : cHighlights;
}
BOOL CTMMultipleSelect::GetFocusRect(int *prow , int *pcol,
int *pcRows, int *pcCols
)
{
*prow = m_iRowLast;
*pcol = 0;
*pcRows = (m_iRowStart <= m_iRowLast) ? m_iRowStart - m_iRowLast - 1
: m_iRowStart - m_iRowLast + 1;
*pcCols = m_ptm->ColCount();
return TRUE;
}
void CTMMultipleSelect::ClearSelection()
{
if (!(m_pisSelection->AnyOnes())) return;
m_pisSelection->ClearAll();
m_iRowStart = 0;
m_iRowLast = 0;
m_ptm->InvalidateImage(0, 0, m_ptm->RowCount(), m_ptm->ColCount());
m_ptm->NotifyViewers (CTextMatrix::FocusChange );
m_ptm->NotifyInterface(CTextMatrix::SelectionChange);
}
void CTMMultipleSelect::SetSelection(CIndicatorSet *pis)
{
ASSERT(m_pisSelection);
if (pis) ChangeRef(m_pisSelection, pis);
else m_pisSelection->ClearAll();
m_iRowStart = 0;
m_iRowLast = 0;
m_ptm->InvalidateImage(0, 0, m_ptm->RowCount(), m_ptm->ColCount());
m_ptm->NotifyViewers (CTextMatrix::FocusChange );
m_ptm->NotifyInterface(CTextMatrix::SelectionChange);
}
// Mouse Events:
void CTMMultipleSelect::StartOnRow(long row, BOOL fShift, BOOL fControl)
{
long iLowChange, iLimitChange;
if (fShift)
{
EndOnRow(row);
return;
}
if ( fControl
|| !m_pisSelection->SelectionCount()
)
{
iLowChange = row;
iLimitChange = row+1;
}
else
{
m_pisSelection->ClearAll();
iLowChange = 0;
iLimitChange = m_ptm->RowCount();
}
int iRowFull;
m_ptm->Data_Indices(row, &iRowFull, 1);
m_usMethod= (m_pisSelection->ChangeBit(iRowFull,
CIndicatorSet::TOGGLE_BIT
) < 0
)? CIndicatorSet::CLEAR_BIT
: CIndicatorSet::SET_BIT;
m_ptm->InvalidateImage(m_iRowStart, 0, 1, m_ptm->ColCount());
m_ptm->InvalidateImage(m_iRowLast , 0, 1, m_ptm->ColCount());
m_iRowStart = row;
m_iRowLast = row;
m_ptm->InvalidateImage(iLowChange, 0, iLimitChange-iLowChange,
m_ptm->ColCount()
);
m_ptm->NotifyViewers (CTextMatrix::FocusChange );
m_ptm->NotifyInterface(CTextMatrix::SelectionChange);
}
void CTMMultipleSelect::OnLButtonDown(UINT nFlags, long row, long col)
{
m_ptm->UpdateImage();
StartOnRow(row, nFlags & MK_SHIFT, nFlags &MK_CONTROL);
m_fMouseButtonDown= TRUE;
}
void CTMMultipleSelect::EndOnRow(long row)
{
long iLowChange, iLimitChange;
long rowLast= m_fMouseButtonDown? m_iRowLast : m_iRowStart;
long oldRowLast= m_iRowLast, oldRowStart= m_iRowStart;
m_iRowLast= row;
if (row > rowLast)
{
iLowChange = rowLast;
iLimitChange = row+1;
}
else
if (row < rowLast)
{
iLowChange = row;
iLimitChange = rowLast+1;
}
else
{
iLowChange = 0;
iLimitChange = 0;
}
long iStart, iLimit, cIndices;
if (row != m_iRowStart)
{
if (row > m_iRowStart)
{
iStart= m_iRowStart+1;
iLimit= row+1;
}
else
{
iStart= row;
iLimit= m_iRowStart;
}
int aiLines[MAX_SCREEN_LINES];
for ( ; iStart < iLimit; iStart+= cIndices)
{
cIndices= iLimit - iStart;
if (cIndices > MAX_SCREEN_LINES) cIndices= MAX_SCREEN_LINES;
int cLines;
cLines= m_ptm->Data_Indices(iStart, (int *) aiLines, UINT(cIndices));
while(cLines)
{
m_pisSelection->ChangeBit(aiLines[--cLines],
m_usMethod
);
}
}
}
m_iRowStart= row;
if (iLowChange > oldRowLast) iLowChange= oldRowLast;
if (iLimitChange <= oldRowLast) iLimitChange= oldRowLast+1;
if (iLowChange != iLimitChange)
{
m_ptm->InvalidateImage(iLowChange, 0, iLimitChange-iLowChange,
m_ptm->ColCount()
);
}
m_ptm->NotifyViewers (CTextMatrix::FocusChange );
if (row != oldRowStart)
m_ptm->NotifyInterface(CTextMatrix::EndOfSelection);
}
void CTMMultipleSelect::OnLButtonUp(UINT nFlags, long row, long col,BOOL bInBox)
{
m_ptm->UpdateImage();
m_fMouseButtonDown= FALSE;
EndOnRow(row);
}
void CTMMultipleSelect::MoveToRow(long row)
{
long iLowChange, iLimitChange;
if (row > m_iRowLast)
{
iLowChange = m_iRowLast;
iLimitChange = row+1;
}
else
if (row < m_iRowLast)
{
iLowChange = row;
iLimitChange = m_iRowLast+1;
}
else
{
iLowChange = 0;
iLimitChange = 0;
}
m_iRowLast= row;
if (iLowChange != iLimitChange)
{
m_ptm->InvalidateImage(iLowChange, 0, iLimitChange-iLowChange,
m_ptm->ColCount()
);
m_ptm->NotifyViewers(CTextMatrix::FocusChange);
}
}
void CTMMultipleSelect::OnMouseMove(UINT nFlags, long row, long col)
{
m_ptm->UpdateImage();
MoveToRow(row);
}
// Keystroke Events:
void CTMMultipleSelect::OnKeyDown(CTextDisplay *ptd, UINT nChar,
UINT nRepCnt,
UINT nFlags
)
{
m_ptm->UpdateImage();
long rowNew= m_iRowLast;
switch(nChar)
{
case VK_SHIFT:
if (m_fShiftDown) return;
m_fShiftDown= TRUE;
int iRowFull;
m_ptm->Data_Indices(m_iRowStart, &iRowFull, 1);
m_usMethod= m_pisSelection->IsBitSet
(iRowFull)? CIndicatorSet::SET_BIT
: CIndicatorSet::CLEAR_BIT;
m_ptm->NotifyViewers(CTextMatrix::FocusChange);
return;
case VK_HOME:
rowNew= 0;
break;
case VK_END:
rowNew= m_ptm->RowCount()-1;
if (rowNew < 0) rowNew= 0;
break;
case VK_PRIOR:
rowNew -= ptd->FullRows();
if (rowNew < 0) rowNew= 0;
break;
case VK_NEXT:
rowNew += ptd->FullRows();
if (rowNew > m_ptm->RowCount()-1)
rowNew = m_ptm->RowCount()-1;
break;
case VK_UP:
if (--rowNew < 0) rowNew= 0;
break;
case VK_DOWN:
if (++rowNew > m_ptm->RowCount()-1) rowNew= m_ptm->RowCount()-1;
break;
case VK_SPACE:
StartOnRow(rowNew, (GetKeyState(VK_SHIFT ) < 0),
(GetKeyState(VK_CONTROL) < 0)
);
default:
return;
}
if (m_fShiftDown)
{
MoveToRow(rowNew);
m_iRowLast= rowNew;
return;
}
long rowLastOld= m_iRowLast;
m_iRowLast= rowNew;
if (rowLastOld == m_iRowStart)
m_ptm->InvalidateImage(m_iRowStart, 0, 1, m_ptm->ColCount());
m_iRowStart= rowNew;
long rowDelta= m_iRowLast - rowLastOld;
long rowFirst, rowLast;
if (rowDelta < 0)
{
rowFirst= m_iRowLast;
rowLast = rowLastOld;
rowDelta= - rowDelta;
}
else
{
rowFirst= rowLastOld;
rowLast = m_iRowLast;
}
if (rowDelta == 1)
m_ptm->InvalidateImage(rowFirst, 0, 2, m_ptm->ColCount());
else
{
m_ptm->InvalidateImage(rowFirst, 0, 1, m_ptm->ColCount());
m_ptm->InvalidateImage(rowLast , 0, 1, m_ptm->ColCount());
}
m_ptm->NotifyViewers(CTextMatrix::FocusChange);
}
void CTMMultipleSelect::OnKeyUp(CTextDisplay *ptd, UINT nChar,
UINT nRepCnt,
UINT nFlags
)
{
m_ptm->UpdateImage();
switch(nChar)
{
case VK_SHIFT:
if (!m_fShiftDown) return;
m_fShiftDown= FALSE;
EndOnRow(m_iRowLast);
m_iRowStart= m_iRowLast;
m_ptm->NotifyViewers(CTextMatrix::FocusChange);
return;
}
}
void CTMMultipleSelect::FilterChanged()
{
if (m_fMouseButtonDown || m_fShiftDown)
{
m_fMouseButtonDown = FALSE;
m_fShiftDown = FALSE;
EndOnRow(m_iRowLast);
}
m_iRowStart = 0;
m_iRowLast = 0;
m_hlType = CHighlight::DOT_BOX_TEXT;
m_fHLOn = (m_ptm->RowCount() && m_ptm->ColCount())? TRUE : FALSE;
m_ptm->NotifyViewers(CTextMatrix::FocusChange);
}