//--------------------------------------------------------------------------- #include #include #pragma hdrstop #include "GameUnit.h" #include "ContentPanel.h" #include "GlobalUnit.h" #include "UtilityUnit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) TColor clrAxis = TColor(RGB(3,5,7)), //XY轴及边框 clrLineTen = TColor(RGB(215,215,215)), //十倍横线 clrLineNor = TColor(0x00EDEDED),// TColor(RGB(250,250,250)), //普通线 clrHeadFont = TColor(RGB(83,109,165)), //头文字 clrSelect = TColor(RGB(150, 155, 159)); TColor u_clrLink[] = {clBlue, clWebLimeGreen, clRed, clWebRoyalBlue}; //--------------------------------------------------------------------------- __fastcall TContentPanel::TContentPanel(TComponent* AOwner) : Vcl::Extctrls::TPanel(AOwner) { Visible = false; DoubleBuffered = true; Ctl3D = false; Color = clBtnHighlight;//clWhite; BorderStyle = bsSingle; OnMouseMove = PanMouseMove; m_nTopGap = m_nLeftBound = m_nTopBound = 0; m_nRows = 50; m_xScaleGap = m_nGap = DPIX(8); m_yZero = 0; m_yScaleGap = m_nGap * 5; m_nRightBound = m_nLeftBound + m_nGap * m_nCols; m_nBottomBound = m_nTopBound + m_nGap * m_nRows; m_nAmoUnit = 100; m_nAmoMax = m_nAmoMin = m_nRowMax = m_nRowMin = 0; m_iType = m_nOriDots = 0; m_iSample = 1; m_iMask = 0; m_iPeakU = m_iPeakL = -1; m_xHalfGap = m_xScaleGap>>1; m_iHint = m_xMaxHint = 0; } //--------------------------------------------------------------------------- void __fastcall TContentPanel::CreateWnd(void) { Vcl::Extctrls::TPanel::CreateWnd(); for(int i=0; i<2; i++){ m_lblHint[i] = new TLabel(NULL); m_lblHint[i]->Visible = false; m_lblHint[i]->Parent = this; m_lblHint[i]->Font->Color = clrHeadFont; // m_lblHint[i]->AutoSize = false; // m_lblHint[i]->Width = 52; // m_lblHint[i]->Height = 16; // m_lblHint[i]->Alignment = taCenter; // m_lblHint[i]->Layout = tlCenter; } UpdateView(0, true); } //--------------------------------------------------------------------------- __fastcall TContentPanel::~TContentPanel() { for(int i=0; i<2; i++) delete m_lblHint[i]; } //--------------------------------------------------------------------------- void __fastcall TContentPanel::SetView(int iType) { if(iType!=m_iType){ m_iType = iType; m_nAmoUnit = iType==3 ? 10 : 100; UpdateView(iType, true); } } //--------------------------------------------------------------------------- void __fastcall TContentPanel::WMSize(TWMSize &msg) { m_nCols = (msg.Width - m_nLeftBound - DPIX(4)) / m_nGap; m_nRightBound = m_nLeftBound + m_nGap * m_nCols; m_xScaleGap = m_nGap; m_xHalfGap = m_xScaleGap>>1; m_aDots.clear(); m_nOriDots = 0; m_iSample = 1; m_iMask = 0; if(!CalcXUnit()) InvalidateRect(Handle, NULL, TRUE); } //--------------------------------------------------------------------------- void __fastcall TContentPanel::Paint() { TRect rtInvalid = Canvas->ClipRect; bool bPeakU = m_iPeakU>=0, bPeakL = m_iPeakL>=0; vector& aDots = m_aDots.empty() ? g_aDots[m_iType] : m_aDots; //绘制选中线 if(m_iHint>0){ int x = m_xZero + m_iHint * m_xScaleGap; Canvas->Pen->Color = clrSelect; Canvas->Pen->Width = 1; Canvas->Pen->Style = psDot; Canvas->MoveTo(x, m_nTopBound+1); Canvas->LineTo(x, m_nBottomBound-1); } int x0 = m_xZero, y0 = m_nTopBound, x1 = x0, l = ( rtInvalid.left - 1 - x0 ) / m_xScaleGap, r = ( rtInvalid.right + 1 - x0 ) / m_xScaleGap + 1, total = aDots.size(); if(total>0) y0 += (int)((m_nRowMax - aDots[0].val) * m_yScale + 0.5); Canvas->Pen->Color = u_clrLink[m_iType]; Canvas->Pen->Width = 2; Canvas->MoveTo( x0, y0 ); for( int i=1; i= i){ //绘制连接线 Canvas->LineTo( x1, y1 ); } else{ Canvas->MoveTo( x1, y1 ); } } } //--------------------------------------------------------------------------- void __fastcall TContentPanel::WMEraseBkgnd(TWMEraseBkgnd &Message) { TCanvas* tempCanvas = new TCanvas; tempCanvas->Handle = Message.DC; //背景色 TRect rect( 0, 0, ClientWidth, ClientHeight ); tempCanvas->Brush->Color = clBtnFace;//clWhite; tempCanvas->FillRect( rect ); //外边框 rect.left = m_nLeftBound; rect.right = m_nRightBound + 1; rect.top = m_nTopBound; rect.bottom = m_nBottomBound + 1; tempCanvas->Brush->Color = clrAxis; tempCanvas->FrameRect( rect ); //纵线 int x = m_xZero, t = rect.top+1, b = rect.bottom-1; tempCanvas->Pen->Color = clrLineNor; for( int i=1; iMoveTo( x, t ); tempCanvas->LineTo( x, b ); } //刻度 tempCanvas->Font->Color = clrHeadFont; tempCanvas->Brush->Style = bsClear; int y = m_nTopGap,//, iY0 = 0, num = m_nRowMax; for( int i=0; i<=10; i++ ){ String sTxt = IntToStr(num); TSize szTxt = tempCanvas->TextExtent( sTxt ); x = m_nLeftBound - szTxt.cx - 1; tempCanvas->TextOut( x, y, sTxt ); num -= m_iAmoUnit; y += m_yScaleGap; } //横线 tempCanvas->Brush->Style = bsSolid; y = m_nTopBound; int l = m_xZero+1, r = rect.right-1; for( int i=1; iPen->Color = i==m_yZero ? clrAxis : i % 5 ? clrLineNor : clrLineTen; tempCanvas->MoveTo( l, y ); tempCanvas->LineTo( r, y ); } delete tempCanvas; Message.Result = true; } //--------------------------------------------------------------------------- void __fastcall TContentPanel::UpdateView(int iType, bool bInit) { if(m_iType!=iType) return; vector& dots = g_aDots[m_iType]; int nTotal = dots.size(); if(bInit){ int nMax(0), nMin(0); if(nTotal>0){ nMax = nMin = dots[0].val; for(int i=1; inMax){ nMax = p; m_iPeakU = i; } else if(p>1; m_aDots.clear(); m_nOriDots = 0; m_iSample = 1; m_iMask = 0; CalcYUnit(nMax, nMin, true); return; } if(!nTotal || m_nOriDots==nTotal) return; int nOriCount = m_nOriDots, nLocCount = m_aDots.size(); bool bYChange = false; for(int i=m_nOriDots; i m_nAmoMax){ m_nAmoMax = p; bYChange = true; if(p > m_nRowMax) m_iPeakU = nTotal - 1; } else if(p < m_nAmoMin){ m_nAmoMin = p; bYChange = true; if(p < m_nRowMin) m_iPeakL = nTotal -1; } } m_nOriDots = nTotal; if(bYChange && CalcYUnit(m_nAmoMax, m_nAmoMin)) return; else if(CalcXUnit()) return; TRect rectDraw; rectDraw.top = m_nTopBound - 1; rectDraw.bottom = m_nBottomBound + 1; if(m_aDots.empty()){ rectDraw.left = m_xZero + (nOriCount-1) * m_xScaleGap; rectDraw.right = rectDraw.Left + (nTotal-nOriCount) * m_xScaleGap + 2; } else{ rectDraw.left = m_xZero + (nLocCount-1) * m_xScaleGap; rectDraw.right = rectDraw.Left + (m_aDots.size()-nLocCount) * m_xScaleGap + 2; } InvalidateRect( Handle, &rectDraw, false ); } //--------------------------------------------------------------------------- void __fastcall TContentPanel::Resample() { vector& dots = g_aDots[m_iType]; m_aDots.clear(); m_aDots.push_back(dots[0]); int total = dots.size(), num = total-20; //保留最少20个点 bool bNoSample = m_iSample==1, bMask = m_iMask>m_iSample; int iS = 0, iM = !bMask, iMask = m_iMask + 1; TDot dtMax = dots[0], dtMin = dots[0]; for(int i=1; idtMax.val) dtMax = dots[i]; else if(dots[i].val=nTmp || dtMax.val==m_nAmoMax) bPushMax = true; else if(dtMax.val<=nTmp || dtMin.val==m_nAmoMin) bPushMax = false; else if(m_aDots.size()>1){ int nSec = m_aDots[m_aDots.size()-2].val; if(nTmp& aDots = m_aDots.empty() ? g_aDots[m_iType] : m_aDots; int total = aDots.size(); int xGap = m_xScaleGap; int xMinGap = 3; if(total * xGap < nWidth){ m_xMaxHint = m_nLeftBound + total * m_xScaleGap - m_xHalfGap; return false; } total = g_aDots[m_iType].size(); while(xGap>xMinGap && total * xGap >= nWidth){ xGap--; } if(xGap!=m_xScaleGap){ m_xScaleGap = xGap; m_xHalfGap = m_xScaleGap>>1; if(total * xGap < nWidth){ // DebugPrint("Change xGap: %d", xGap); m_xMaxHint = m_nLeftBound + total * xGap - m_xHalfGap; if(m_iHint>0){ m_iHint = 0; m_lblHint[0]->Visible = false; m_lblHint[1]->Visible = false; } InvalidateRect( Handle, NULL, true ); return true; } } int nCol = nWidth / xGap; int iSample = m_iSample, iMask = m_iMask; while((total-20) / iSample + 20 + 10 > nCol){ if(iMask<=iSample) iMask = iSample + 10; while(iMask>iSample && (total-20) * iMask / ((iMask+1)*iSample) + 20 + 10 > nCol){ iMask--; } if(iMask>iSample) break; iSample++; } if(iSample!=m_iSample || iMask!=m_iMask){ m_iMask = iMask; m_iSample = iSample; // DebugPrint("Change sample: %d mask: %d", iSample, iMask); } Resample(); if(m_iHint>0){ m_iHint = 0; m_lblHint[0]->Visible = false; m_lblHint[1]->Visible = false; } InvalidateRect( Handle, NULL, true ); return true; } //--------------------------------------------------------------------------- bool __fastcall TContentPanel::CalcYUnit(int nMax, int nMin, bool bInit) { if(bInit || nMax > m_nRowMax || nMin < m_nRowMin ){ //初始化||范围变动 int scale = 100 / m_nAmoUnit; if(nMax==nMin){ m_nRowMax = (nMax / m_nAmoUnit + 1) * m_nAmoUnit; m_nRowMin = m_nRowMax - 2 * m_nAmoUnit; if(m_nRowMax>0 && m_nRowMin<0) m_yZero = 25; else m_yZero = 0; } else if(nMax>0 && nMin<0){ nMax = (nMax / m_nAmoUnit + ((nMax % m_nAmoUnit) ? 1 : 0)) * m_nAmoUnit; nMin = (nMin / m_nAmoUnit - ((nMin % m_nAmoUnit) ? 1 : 0)) * m_nAmoUnit; //找可整除的0轴 int m = (nMax - nMin) * scale / 50; if(0 == (nMin * scale) % m){ m_nRowMax = nMax; m_nRowMin = nMin; } else{ int rMax = nMax, rMin = nMin, tmpMin = nMin, rm = m_iType==3 ? 10000 : 10000000; //寻找最佳方案 bool bUp = g_aDots[m_iType].back().val > 0; for(int m1=m; m1 < (bUp ? rm : rm+1); m1+=2){ //最后的数据为负,优先扩下半区,或者尽量上下同扩 if(m1>m && 0 == tmpMin % m1){ rMax = nMax; rMin = tmpMin; rm = m1; break; } int tmpMax = nMax; for(int m2=m1+2; -tmpMin>=m2 && m2 < (bUp ? rm+1: rm); m2+=2){ //最后的数据为正,优先扩上半区 tmpMax += m_nAmoUnit; if(0==tmpMin % m2){ rMax = tmpMax; rMin = tmpMin; rm = m2; break; } } tmpMin -= m_nAmoUnit; } m_nRowMax = rMax; m_nRowMin = rMin; m = rm; } int n = - m_nRowMin * scale / m; if(n<1) n = 1; else if(n>49) n = 49; m_yZero = 50 - n; } else{ m_nRowMax = nMax / m_nAmoUnit * m_nAmoUnit; if(nMax > 0 && nMax % m_nAmoUnit) m_nRowMax += m_nAmoUnit; m_nRowMin = nMin / m_nAmoUnit * m_nAmoUnit; if(nMin < 0 && nMin % m_nAmoUnit) m_nRowMin -= m_nAmoUnit; m_yZero = 0; } TSize szTxt1 = Canvas->TextExtent(IntToStr(m_nRowMax)), szTxt2 = Canvas->TextExtent(IntToStr(m_nRowMin)); // int hhTxt = szTxt1.cy / 2; // if(hhTxt<16){ // m_nTopGap = 16 - hhTxt; // m_nTopBound = 16; // } // else{ // m_nTopGap = 0; // m_nTopBound = hhTxt; // } m_nTopBound = szTxt1.cy; m_nTopGap = szTxt1.cy / 2; m_nBottomBound = m_nTopBound + m_nGap * m_nRows; m_nLeftBound = max(szTxt1.cx, szTxt2.cx) + 2; m_xZero = m_nLeftBound; m_iAmoUnit = (m_nRowMax - m_nRowMin) / 10; m_yScale = 5.0 * m_nGap / m_iAmoUnit; m_nCols = (ClientWidth - m_nLeftBound - DPIX(4)) / m_nGap; m_nRightBound = m_nLeftBound + m_nGap * m_nCols; CalcXUnit(); InvalidateRect( Handle, NULL, true ); return true; } return false; } //--------------------------------------------------------------------------- void __fastcall TContentPanel::PanMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { ResetIdle(); int iHit = HitTest(X, Y); if(m_iHint!=iHit) ShowTimeHint(iHit); } //--------------------------------------------------------------------------- void __fastcall TContentPanel::PanKeyDown(WORD Key) { if(Key==37){ if(!m_iHint){ vector& aDots = m_aDots.empty() ? g_aDots[m_iType] : m_aDots; if(aDots.size()>1) ShowTimeHint(aDots.size()-1); } else if(m_iHint>1){ ShowTimeHint(m_iHint-1); } } else if(Key==39){ vector& aDots = m_aDots.empty() ? g_aDots[m_iType] : m_aDots; if(m_iHint>0){ if(m_iHint1){ ShowTimeHint(1); } } } //--------------------------------------------------------------------------- int __fastcall TContentPanel::HitTest(int x, int y) { int iHit = 0; if(y>m_nTopBound && ym_nLeftBound && x0){ int x = m_xZero + m_iHint * m_xScaleGap; rectDraw.left = x - 1; rectDraw.right = x + 1; InvalidateRect( Handle, &rectDraw, false ); } m_iHint = iHint; if(iHint>0){ int x = m_xZero + iHint * m_xScaleGap; rectDraw.left = x - 1; rectDraw.right = x + 1; InvalidateRect( Handle, &rectDraw, false ); vector& aDots = m_aDots.empty() ? g_aDots[m_iType] : m_aDots; int ts = aDots[iHint].ts - 57600, r = ts % 86400, h, m, s; h = r / 3600, r -= h * 3600; m = r / 60, r -= m * 60; s = r; m_lblHint[0]->Top = m_nTopBound - m_lblHint[0]->Height; m_lblHint[0]->Caption = IntToStr(aDots[iHint].val); m_lblHint[1]->Top = m_nBottomBound + 1; m_lblHint[1]->Caption = Format(String("%.2d:%.2d:%.2d"), ARRAYOFCONST((h, m, s))); int xMin = m_xZero-1, xMax = m_nRightBound+2; for(int i=0; i<2; i++){ int l = x - (m_lblHint[i]->Width>>1); if(l xMax - m_lblHint[i]->Width) l = xMax - m_lblHint[i]->Width; m_lblHint[i]->Left = l; m_lblHint[i]->Visible = true; } } else{ m_lblHint[0]->Visible = false; m_lblHint[1]->Visible = false; } } //---------------------------------------------------------------------------