Files
AC_Pro/TableViewUnit.cpp
2026-06-13 00:05:19 +08:00

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++;
}
}
//---------------------------------------------------------------------------