581 lines
13 KiB
C++
581 lines
13 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <vcl.h>
|
|
#pragma hdrstop
|
|
|
|
#include "TableViewUnit.h"
|
|
//---------------------------------------------------------------------------
|
|
#pragma package(smart_init)
|
|
//---------------------------------------------------------------------------
|
|
#define CelOFF 1
|
|
#define HgtERROR 0
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TTableView::TTableView(TComponent* Owner) : TScrollView(Owner)
|
|
{
|
|
OnChangeSBPos = DoChgPos;
|
|
OnChangeSize = DoChgSize;
|
|
OnHgtTitle = DoHgtTitle;
|
|
OnHgtBottom = DoHgtBottom;
|
|
|
|
FIndFocus = NOSET;
|
|
FIndSel = NOSET;
|
|
FCount = 0;
|
|
FHgtSmall = NOSET;
|
|
m_Title = NULL;
|
|
m_Bottom = NULL;
|
|
|
|
OnMouseWheel = DoMouseWheel;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TTableView::~TTableView()
|
|
{
|
|
DoTableInit();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TTableView::ReloadData(int iCellIndex, SBS iSBS, int iTopline)
|
|
{
|
|
bool bRet = true;
|
|
|
|
DoTableInit();
|
|
|
|
if( FOnTitle ) { //set title
|
|
|
|
m_Title = (TPanelDB *)FOnTitle(this);
|
|
if( m_Title ) m_Title->Parent = this;
|
|
}
|
|
|
|
if( FOnBottom ) { //set Bottom
|
|
|
|
m_Bottom = (TPanelDB *)FOnBottom(this);
|
|
if( m_Bottom ) m_Bottom->Parent = this;
|
|
}
|
|
|
|
if( FOnCellHgt && FOnMDNum && FOnMDCell )
|
|
{
|
|
m_DBNum = FOnMDNum(this); //set data num
|
|
if( m_DBNum<=0 ) bRet = false;
|
|
|
|
if( bRet ) {
|
|
|
|
for( int index=0; index<m_DBNum; index++ ){ //set data show height
|
|
|
|
int iCurHgt = FOnCellHgt(this, index);
|
|
if( iCurHgt<=HgtERROR ) {
|
|
bRet = false; //cell nHeight error
|
|
m_VCHGT.clear();
|
|
break;
|
|
}
|
|
m_VCHGT.push_back(iCurHgt);
|
|
}
|
|
|
|
if( bRet ) {
|
|
|
|
DoLstInitial();
|
|
SetSB(m_PosTotal, m_PosPage, m_PosBegin);
|
|
|
|
TStateBtn *pCellTmp = NULL;
|
|
for(int index=0; index<m_DBNeed; index++){ //set data cell content
|
|
|
|
int iAdCell = FOnMDCell(this, index);
|
|
pCellTmp = (TStateBtn *)iAdCell;
|
|
if( pCellTmp ) m_LstBtn.push_back(pCellTmp);
|
|
}
|
|
|
|
if( OnChange ) OnChange(this);
|
|
|
|
if( NOSET!=iCellIndex ) { SetCellInd(iCellIndex); } //set begin show pos
|
|
else if( SBS_NONE!=iSBS) { SetSBPos(iSBS, iTopline); }
|
|
else {
|
|
DoLstChg();
|
|
}
|
|
}
|
|
}
|
|
|
|
}else bRet = false; //cell num error
|
|
|
|
if( !bRet ) {
|
|
FIndSel = NOSET;
|
|
SetSB(0, 0, 0);
|
|
Paint();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TTableView::DoLstInitial()
|
|
{
|
|
if( 0==m_VCHGT.size() ) return false;
|
|
|
|
int nHeight = getContentHeight();
|
|
|
|
// get smallest nHeight
|
|
int iSmlHgt = m_VCHGT[0];
|
|
for( int i=1; i<m_VCHGT.size(); i++ ) {
|
|
if( iSmlHgt>m_VCHGT[i] ) iSmlHgt = m_VCHGT[i];
|
|
}
|
|
|
|
int iSmlHgtTmp = iSmlHgt;
|
|
if(iSmlHgt>nHeight)
|
|
iSmlHgtTmp = iSmlHgt = (iSmlHgt-nHeight)%nHeight;
|
|
if( (HgtSmall!=NOSET) && (HgtSmall<iSmlHgtTmp) )
|
|
iSmlHgtTmp = HgtSmall;
|
|
|
|
//get each cell pos num range
|
|
int iCellShowHgt = 0;
|
|
int iCellShowNum = 0;
|
|
int iPosNumCur = 0;
|
|
int iPosNumTotal = 0;
|
|
|
|
bool bSBOK = false;
|
|
for( int i=0; i<m_VCHGT.size(); i++ ) {
|
|
|
|
int iPlus = ( (m_VCHGT[i]%iSmlHgtTmp)==0 ) ? 0:1;
|
|
iPosNumCur = m_VCHGT[i]/iSmlHgtTmp + iPlus;
|
|
iPosNumTotal += iPosNumCur;
|
|
|
|
m_VCPOS.push_back(iPosNumTotal);
|
|
|
|
if(!bSBOK){
|
|
|
|
iCellShowNum++;
|
|
iCellShowHgt += m_VCHGT[i];
|
|
|
|
if( iCellShowHgt>=nHeight ) {
|
|
|
|
iCellShowNum = nHeight/iSmlHgt;
|
|
m_PosPage = nHeight/iSmlHgtTmp;
|
|
|
|
bSBOK = true;
|
|
}
|
|
}
|
|
}
|
|
//get sb info
|
|
m_PosTotal = iPosNumTotal;
|
|
|
|
//no sb will show
|
|
if(iCellShowHgt<nHeight) m_PosPage = m_PosTotal;
|
|
|
|
//smallest cell nHeight
|
|
m_HgtSmall = iSmlHgtTmp;
|
|
|
|
//cell visible num + off 2
|
|
m_DBNeed = iCellShowNum + CelOFF*2;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TTableView::DoTableInit()
|
|
{
|
|
m_bTop = m_bBom = false;
|
|
|
|
m_PosTotal = m_PosPage = m_PosBegin = 0;
|
|
|
|
m_DBNum = m_DBNeed = 0;
|
|
m_IndTop = m_IndBeg = 0;
|
|
m_UIOffMerge = CelOFF;
|
|
m_UIOff = 0;
|
|
|
|
m_HgtSmall = NOSET;
|
|
m_HgtTop = m_HgtOver = 0;
|
|
|
|
|
|
m_VCHGT.clear();
|
|
m_VCPOS.clear();
|
|
m_VCCHG.clear();
|
|
|
|
BtnClear();
|
|
|
|
SAFE_DELETE(m_Title);
|
|
SAFE_DELETE(m_Bottom);
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::DoLstChg(CELLS eCELLS, int Offset)
|
|
{
|
|
DoLstChgPos(eCELLS, Offset);
|
|
DoLstChgCel(eCELLS);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::DoLstChgPos(CELLS eCELLS, int Offset)
|
|
{
|
|
|
|
bool bPage = false;
|
|
bool bDown = true;
|
|
bool bMerge = true; //get cell change list
|
|
int iMergePos = 0;
|
|
int iCellChgNum = 0;
|
|
int iCellTop = 0; //get cell top value
|
|
int iIndTop = m_IndTop; //get cell index: top and begin
|
|
|
|
switch(eCELLS)
|
|
{
|
|
case CELLS_Default:
|
|
{
|
|
m_IndTop = m_IndBeg = 0;
|
|
m_HgtTop = 0;
|
|
m_UIOff = 0;
|
|
return;
|
|
} break;
|
|
case CELLS_Page:
|
|
{
|
|
bPage = true;
|
|
bDown = false;
|
|
bMerge = false;
|
|
|
|
iIndTop = m_IndTop = m_IndBeg;
|
|
m_HgtTop = 0;
|
|
m_UIOff = 0;
|
|
} break;
|
|
case CELLS_Up:
|
|
{
|
|
bDown = false;
|
|
//--------------when just show > needs cell
|
|
//merge
|
|
if(m_UIOff-Offset<0)
|
|
{
|
|
bMerge = true;
|
|
if(m_UIOff!=0){
|
|
iCellChgNum = Offset - m_UIOff;
|
|
}else{
|
|
iCellChgNum = Offset;
|
|
}
|
|
m_IndTop -= iCellChgNum;
|
|
m_UIOff = 0;
|
|
|
|
//--------------when just show between needs cell
|
|
}else{
|
|
|
|
bMerge = false;
|
|
iCellChgNum = 0;
|
|
m_UIOff -= Offset;
|
|
}
|
|
} break;
|
|
case CELLS_Down:
|
|
{
|
|
//--------------when just show > needs cell
|
|
//merge
|
|
if(m_UIOff+Offset>m_UIOffMerge ||
|
|
m_UIOff==1)
|
|
{
|
|
bMerge = true;
|
|
if(m_UIOff<m_UIOffMerge){
|
|
iCellChgNum =
|
|
Offset - (m_UIOffMerge - m_UIOff);
|
|
}else{
|
|
iCellChgNum = Offset;
|
|
}
|
|
m_IndTop += iCellChgNum;
|
|
m_UIOff = m_UIOffMerge;
|
|
|
|
//--------------when just show between needs cell
|
|
}else{
|
|
|
|
bMerge = false;
|
|
iCellChgNum = 0;
|
|
m_UIOff += Offset;
|
|
}
|
|
|
|
bDown = true;
|
|
} break;
|
|
default: break;
|
|
}
|
|
|
|
int iCelInd = 0;
|
|
BTNLST::iterator lst_FCell = m_LstBtn.begin();
|
|
for( VCINT::iterator vc_FHgt = (m_VCHGT).begin() + iIndTop;
|
|
vc_FHgt != m_VCHGT.end(),
|
|
lst_FCell != m_LstBtn.end();
|
|
vc_FHgt++,
|
|
lst_FCell++ )
|
|
{
|
|
if(bPage) { //move too fast, change all the cells
|
|
|
|
if( iCelInd<m_DBNeed )
|
|
m_VCCHG.push_back( iIndTop+iCelInd );
|
|
iCelInd++;
|
|
continue;
|
|
}
|
|
|
|
if(bMerge) //judge the mergePos, ready for merge the new celllist
|
|
{
|
|
if( (bDown&&(iIndTop+iCelInd==m_IndTop)) ||
|
|
(!bDown&&(iIndTop+iCelInd==iIndTop+m_DBNeed-iCellChgNum)) )
|
|
iMergePos = iCelInd;
|
|
}
|
|
|
|
// m_VCCHG >> save the change cells's source index
|
|
if(iCelInd<iCellChgNum) {
|
|
|
|
if(bDown){ // down last cells change
|
|
m_VCCHG.push_back(iIndTop+m_DBNeed+iCelInd);
|
|
}else{ // up first cells change
|
|
m_VCCHG.push_back(m_IndTop+iCelInd);
|
|
}
|
|
}
|
|
|
|
// [m_IndTop, m_IndBeg) >> iCellTop
|
|
if( m_IndBeg-m_UIOffMerge<=iIndTop+iCelInd &&
|
|
iIndTop+iCelInd<m_IndBeg )
|
|
{
|
|
iCellTop += *vc_FHgt;
|
|
}
|
|
|
|
iCelInd++;
|
|
}
|
|
|
|
if(bPage) { return; }
|
|
|
|
m_HgtTop = -iCellTop;
|
|
|
|
if( bMerge ) {
|
|
|
|
if( iMergePos ) {
|
|
|
|
BTNLST::iterator lst_FCell;
|
|
lst_FCell = m_LstBtn.begin();
|
|
advance(lst_FCell, iMergePos);
|
|
m_LstBtn.splice(m_LstBtn.begin(), m_LstBtn, lst_FCell, m_LstBtn.end());
|
|
}
|
|
else {
|
|
int index = m_IndTop;
|
|
m_VCCHG.clear();
|
|
for( BTNLST::iterator lst_FCell = (m_LstBtn).begin();
|
|
lst_FCell != (m_LstBtn).end();
|
|
lst_FCell++ )
|
|
{
|
|
m_VCCHG.push_back(index);
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::DoLstChgCel(CELLS eCELLS, bool bPaint)
|
|
{
|
|
if(!FOnMDCell ) return;
|
|
|
|
for( VCINT::iterator vc_FChg = (m_VCCHG).begin();
|
|
vc_FChg != (m_VCCHG).end();
|
|
vc_FChg++ )
|
|
{
|
|
FOnMDCell(this, *vc_FChg);
|
|
}
|
|
|
|
if( bPaint ) Paint();
|
|
|
|
m_VCCHG.clear();
|
|
|
|
if( OnChange )
|
|
OnChange(this);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TTableView::IsCellVisible(int iCellIndex)
|
|
{
|
|
bool bVisible = true;
|
|
|
|
if( iCellIndex<m_IndBeg ) bVisible = false;
|
|
|
|
if( iCellIndex>=GetCellBom() ) bVisible = false;
|
|
|
|
return bVisible;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::getContentHeight()
|
|
{
|
|
int nHeight = Height;
|
|
if( m_Title ) nHeight -= m_Title->Height;
|
|
if( m_Bottom ) nHeight -= m_Bottom->Height;
|
|
return nHeight;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TStateBtn* __fastcall TTableView::GetCellAds(int iCellIndex)
|
|
{
|
|
TStateBtn *rowCellTmp = NULL;
|
|
|
|
int index = 0;
|
|
BTNLST::iterator lst_FCell;
|
|
for( lst_FCell = (m_LstBtn).begin();
|
|
lst_FCell != (m_LstBtn).end();
|
|
lst_FCell++)
|
|
{
|
|
if(m_IndTop+index == iCellIndex){
|
|
rowCellTmp = *lst_FCell;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
return rowCellTmp;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::GetCellHgt(int iCellIndex)
|
|
{
|
|
if( 0<=iCellIndex && iCellIndex<=m_DBNum-1 )
|
|
return m_VCHGT[iCellIndex];
|
|
|
|
return 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::GetCellBeg()
|
|
{
|
|
return m_IndBeg;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::GetCellBom()
|
|
{
|
|
int nHeight = m_RtContent.Height();
|
|
|
|
int indBeg = m_IndBeg;
|
|
int iCurTop = m_HgtOver;
|
|
int index = 0;
|
|
for( ; index<m_DBNum; index++ ) {
|
|
iCurTop += m_VCHGT[index];
|
|
if( iCurTop>=nHeight ) break;
|
|
}
|
|
|
|
return indBeg+index+1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::GetCellNum()
|
|
{
|
|
return m_DBNum;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::SetCellInd(int iCellIndex)
|
|
{
|
|
if( iCellIndex<0 || iCellIndex>m_DBNum-1) return;
|
|
|
|
int iTopLine = 0;
|
|
if( iCellIndex!=0 ) iTopLine = m_VCPOS[iCellIndex-1];
|
|
|
|
SetSBPos(SBS_POS, iTopLine);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::SetSBPos(SBS iSBS, int iTopline)
|
|
{
|
|
short ScrollCode = iSBS;
|
|
|
|
if(iSBS==SBS_TOP){
|
|
|
|
iTopline = 0;
|
|
|
|
}else if(iSBS==SBS_BOTTOM){
|
|
|
|
iTopline = m_PosTotal-m_PosPage;
|
|
}
|
|
|
|
DoChgPos(this, ScrollCode, iTopline);
|
|
SetSB(m_PosTotal, m_PosPage, m_PosBegin);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::DoChgPos(TObject *Sender, short ScrollCode, int iTopLine)
|
|
{
|
|
if( iTopLine<0 ) {
|
|
iTopLine = 0;
|
|
}
|
|
else if(iTopLine>m_PosTotal-m_PosPage ) {
|
|
iTopLine = m_PosTotal-m_PosPage;
|
|
}
|
|
|
|
if( m_bTop && (ScrollCode==SB_LINEUP||ScrollCode==SB_PAGEUP ) ){
|
|
if(FOnMDTop) FOnMDTop(this);
|
|
return;
|
|
}
|
|
else if( m_bBom && (ScrollCode==SB_LINEDOWN||ScrollCode==SB_PAGEDOWN ) ){
|
|
if(FOnMDBottom) FOnMDBottom(this);
|
|
return;
|
|
}
|
|
else if( iTopLine<0 || iTopLine>m_PosTotal ) return;
|
|
m_bTop = (0==iTopLine)?true:false;
|
|
m_bBom = (m_PosTotal-m_PosPage==iTopLine)?true:false;
|
|
|
|
//get CELLS
|
|
CELLS eCELLS;
|
|
if(abs(m_PosBegin-iTopLine)>=m_PosPage+2) eCELLS = CELLS_Page;
|
|
else if(m_PosBegin<iTopLine) eCELLS = CELLS_Down;
|
|
else if(m_PosBegin>iTopLine) eCELLS = CELLS_Up;
|
|
|
|
//get new m_IndBeg
|
|
int iIndChange, iPosCur, iPosPre;
|
|
iIndChange = iPosCur = iPosPre = 0;
|
|
|
|
int front, end, mid;
|
|
front = 0;
|
|
end = m_VCPOS.size()-1;
|
|
mid = (front+end)/2;
|
|
VCINT::iterator vc_FPos = (m_VCPOS).begin();
|
|
iPosCur = *(vc_FPos+mid);
|
|
if(mid==0) iPosPre = 0;
|
|
else iPosPre = *(vc_FPos+mid-1);
|
|
while( front<=end ) {
|
|
|
|
if(iPosPre<=iTopLine && iTopLine<iPosCur) {
|
|
iIndChange = mid;
|
|
break;
|
|
}
|
|
|
|
if(iPosCur<=iTopLine) front = mid+1;
|
|
else if(iPosCur>iTopLine) end = mid;
|
|
|
|
mid = (front+end)/2;
|
|
iPosCur = *(vc_FPos+mid);
|
|
if(mid==0) iPosPre = 0;
|
|
else iPosPre = *(vc_FPos+mid-1);
|
|
}
|
|
|
|
//get new m_IndBeg to it's pre index >> m_HgtOver
|
|
int iPosBeginNum = 0;
|
|
if( iIndChange != 0 ) iPosBeginNum = *(m_VCPOS.begin()+iIndChange-1);
|
|
int iABS = abs(iPosBeginNum-iTopLine);
|
|
m_HgtOver = -iABS*m_HgtSmall;
|
|
|
|
if( iIndChange!=m_IndBeg ) { //change m_IndBeg
|
|
|
|
int indBeginTmp = m_IndBeg;
|
|
m_IndBeg = iIndChange;
|
|
|
|
DoLstChg( eCELLS, abs(indBeginTmp-iIndChange) );
|
|
|
|
}else { //change m_IndBeg over hegiht
|
|
|
|
Paint();
|
|
}
|
|
|
|
m_PosBegin = iTopLine;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::DoHgtTitle(TObject *Sender)
|
|
{
|
|
if( m_Title) return m_Title->Height;
|
|
return 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TTableView::DoHgtBottom(TObject *Sender)
|
|
{
|
|
if( m_Bottom) return m_Bottom->Height;
|
|
return 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TTableView::DoPaintLst(TCanvas *pCanvas)
|
|
{
|
|
int iTop, iLeft, iWidth, iHeight;
|
|
iTop = m_HgtTop + m_HgtOver + m_RtContent.Top;
|
|
iLeft = m_RtContent.Left;
|
|
iWidth = m_RtContent.Width();
|
|
|
|
int iIndex = 0;
|
|
for(BTNLST::iterator lstBtn=m_LstBtn.begin(); lstBtn!=m_LstBtn.end(); lstBtn++) {
|
|
|
|
if(m_IndTop+iIndex>m_VCHGT.size()-1) { break; }
|
|
|
|
iHeight = m_VCHGT[m_IndTop+iIndex];
|
|
|
|
(*lstBtn)->SetBounds( iLeft, iTop, iWidth, iHeight );
|
|
(*lstBtn)->Paint(pCanvas);
|
|
|
|
iTop += iHeight;
|
|
iIndex++;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|